Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
1
third-party/vendor/swc_common/.cargo-checksum.json
vendored
Normal file
1
third-party/vendor/swc_common/.cargo-checksum.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"04276bd9c80435b465ef21047532fccd4d98b9d4ac10cfbea6851171c8ebf199","benches/serde.rs":"14c09feab0336e7fc6492b35c60d6758b04ed557867244a2aff0a141e1952f2c","src/collections.rs":"653a45b5ec102fd58bcddb4442e1f93c32019f83bf908a1fcb976af98b49d21d","src/comments.rs":"2868051ab0f545564cf18577919e2bb200161785fa0f8a2f50d23dc68a2ba4a8","src/eq.rs":"a418e6043b6127d48bbf9d37bec03d771f2ff28b2c1c3257e74aa6a0ff2fac27","src/errors/diagnostic.rs":"ebedd825054a9e16330b0acc475743effc9e1caafcb5b50eec702a0b8d1379f3","src/errors/diagnostic_builder.rs":"0af3b5d81325703db3e3fe9bb2bf91b1d531d7000119b7cc405d967a81a594ba","src/errors/emitter.rs":"b7fb7f579db38c3377939fe02173f12c99ec55782a4fd964c697a7041214f07f","src/errors/lock.rs":"7c586f265fcebbe03c9e7e79cbb903ce854d0e97ab799487a14e2d602d72aff2","src/errors/mod.rs":"b90768616b132b028c626929cb0ec61763859042b4bdc703a556bba469aac5ed","src/errors/snippet.rs":"ab806111208f3b68dbd00322ebdf7d0d25d10b255186ec415e67843e89db3e31","src/errors/styled_buffer.rs":"f10de25391cc0eb8269d500e5851931be7deb0a1826c8098771059a899b20138","src/errors/tests.rs":"8b49cc549453e4f38d4fcae2a8f434239fbf89ff0cb495220bb56e8914bd2bef","src/input.rs":"7ddf8537120df1731e0cb6e14c3578abd991ef25cf12ac6d70249c27dcfdbfd7","src/iter.rs":"b13a6f180264e6b17dec3183f7c76e2401b214862661837ce53370d57a16c25a","src/lib.rs":"4e91b0ee8cd7cd5a8ebd8286c05dd864602ab8db65c814a34f38c8d6d00cf9ed","src/pass.rs":"4ec031d53186af0043854c011351ebc7a788fd807f5a1baea648049b5a3f500e","src/plugin/diagnostics.rs":"201a5027967f1f64dfcad298d51cd36b40fa5715f08853a7a4925cb441120ec4","src/plugin/metadata.rs":"a1d780b48a8ba3d085d7ff077bcd4fee84e4787dade06ca4288975dfc890c387","src/plugin/mod.rs":"a871819e79631771f8795ebf6269676b03adb314e3998c1e5ca9076632d6413b","src/plugin/serialized.rs":"3752970a82520e9016e4736e86890a2f410c704c7bd3dd74e298e9c2c6769b71","src/pos.rs":"94eaee8fc19c55c80c36151d1d80879fe691801ff8484e6b1ef3fa42b9a1ffa2","src/private/mod.rs":"b97e4dbbdf488d16796d7dd7350fd1c5891292ee4adf9ba34af9444346f68fb3","src/rustc_data_structures.rs":"a156eb041a92793c2452a5aa3d372a02d7d8b1c116b80169f1179b32a4408e3e","src/rustc_data_structures/stable_hasher.rs":"d3f164b74d355c04d069ddbe5757203a818f4c4cb818a959517d0bb8b36d30e8","src/serializer.rs":"ed3343a0c5560eedf231f7c7a2204d1333a139fddf61ff03d5ebbdcf6196646c","src/source_map.rs":"08edfc6c9b47d03380c1fa6194237213b52748cddd774dfb14171ea4e591c578","src/sync.rs":"16f8178d95970fd3255c098f864aa4d93cb6d4888eb84591e4ad73b70f422ca2","src/syntax_pos.rs":"81802095f35dbc1acc8075f73cd417d2c3c089f560b3c9798784e69b448fe8b1","src/syntax_pos/analyze_source_file.rs":"308199df826016d1a55a79148cc1a98e4dafb7460145f7a7ac6f0f822bfb5e5b","src/syntax_pos/hygiene.rs":"24a16ef2eda974b1d6f6cf69d600e9fcb8dcdf75b372d250c7329af4098cfd2a","src/util/iter.rs":"4a2310afe42287e4980fdb93a44ac2d17f89ea2f3f86a3f3e2d01b495a6c14c7","src/util/map.rs":"47692e3ca61a40b263aa2caedd79369615494f30355cf7276b5e0573ace4e774","src/util/mod.rs":"ae5f49e6c24a0c0a0ec3ccd9a5625a44a6cf0dfb98f4e814c4ba33bacfa5be62","src/util/move_map.rs":"2dc1db8d437f1dcf0e8c46c95a7e9f91f981700c27f01b5efd65c07942d380ec","src/util/take.rs":"686c4de62c9c251d708279cb0f83c110bbbd7a9e3dc95ef19f5c496311ea3e39","tests/ast_serde.rs":"c1e60e98b8f982f7c603c5dfd0295c4aea4f0a02e5531e9b32875d7d1732ff13","tests/attr_interop.rs":"975d73e20b58a34f19f295de86bb452ea20610122dce0dba03024dc3aae1929d","tests/concurrent.js":"03931ddf1633a856c1a995ebbd2f0791d669bf7130cedb447b003a7fd0110b12","tests/concurrent.rs":"cb1722104847d986fbc0c9f8cc031b32b68b472da621bba9323112932136dd06","tests/empty.rs":"4797b297c9c4ffb03ea3c2633be9f1a388218d2bab77e8b6644825fbe8ccb1f9","tests/issue_3159.rs":"6163196b89c925d5f515a072a46191c5644e03b3bd76aba122951b8f6dabb64e","tests/source_map.rs":"b15d4f77d29dbfc966ece2b0599f04ea7c3687232d0fbe7baa4056aa83fa7e8c","tests/spanned_attr.rs":"bff3bca5bf8bd69e4d4f0f334784959f598cc8dcc7f67c2cabb3c3bdd7680272"},"package":"39cb7fcd56655c8ae7dcf2344f0be6cbff4d9c7cb401fe3ec8e56e1de8dfe582"}
|
||||
176
third-party/vendor/swc_common/Cargo.toml
vendored
Normal file
176
third-party/vendor/swc_common/Cargo.toml
vendored
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "swc_common"
|
||||
version = "0.32.0"
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
description = "Common utilities for the swc project."
|
||||
documentation = "https://rustdoc.swc.rs/swc_common/"
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docsrs",
|
||||
]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[[bench]]
|
||||
name = "serde"
|
||||
harness = false
|
||||
|
||||
[dependencies.ahash]
|
||||
version = "0.8.3"
|
||||
optional = true
|
||||
|
||||
[dependencies.anyhow]
|
||||
version = "1.0.71"
|
||||
optional = true
|
||||
|
||||
[dependencies.arbitrary]
|
||||
version = "1"
|
||||
features = ["derive"]
|
||||
optional = true
|
||||
|
||||
[dependencies.ast_node]
|
||||
version = "0.9.5"
|
||||
|
||||
[dependencies.atty]
|
||||
version = "0.2"
|
||||
optional = true
|
||||
|
||||
[dependencies.better_scoped_tls]
|
||||
version = "0.1.1"
|
||||
|
||||
[dependencies.bytecheck]
|
||||
version = "0.6.10"
|
||||
optional = true
|
||||
|
||||
[dependencies.cfg-if]
|
||||
version = "1.0.0"
|
||||
|
||||
[dependencies.either]
|
||||
version = "1.5"
|
||||
|
||||
[dependencies.from_variant]
|
||||
version = "0.1.6"
|
||||
|
||||
[dependencies.new_debug_unreachable]
|
||||
version = "1.0.4"
|
||||
|
||||
[dependencies.num-bigint]
|
||||
version = "0.4"
|
||||
|
||||
[dependencies.once_cell]
|
||||
version = "1.18.0"
|
||||
|
||||
[dependencies.parking_lot]
|
||||
version = "0.12.1"
|
||||
optional = true
|
||||
|
||||
[dependencies.rkyv]
|
||||
version = "=0.7.42"
|
||||
features = [
|
||||
"strict",
|
||||
"validation",
|
||||
]
|
||||
optional = true
|
||||
|
||||
[dependencies.rustc-hash]
|
||||
version = "1.1.0"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.119"
|
||||
features = ["derive"]
|
||||
|
||||
[dependencies.siphasher]
|
||||
version = "0.3.9"
|
||||
|
||||
[dependencies.sourcemap]
|
||||
version = "6"
|
||||
optional = true
|
||||
|
||||
[dependencies.string_cache]
|
||||
version = "0.8.7"
|
||||
|
||||
[dependencies.swc_atoms]
|
||||
version = "0.5.9"
|
||||
|
||||
[dependencies.swc_eq_ignore_macros]
|
||||
version = "0.1.2"
|
||||
|
||||
[dependencies.swc_visit]
|
||||
version = "0.5.7"
|
||||
|
||||
[dependencies.termcolor]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.tracing]
|
||||
version = "0.1.37"
|
||||
|
||||
[dependencies.unicode-width]
|
||||
version = "0.1.4"
|
||||
|
||||
[dependencies.url]
|
||||
version = "2.4.0"
|
||||
|
||||
[dev-dependencies.criterion]
|
||||
version = "0.5"
|
||||
|
||||
[dev-dependencies.rayon]
|
||||
version = "1"
|
||||
|
||||
[dev-dependencies.serde_json]
|
||||
version = "1"
|
||||
|
||||
[features]
|
||||
__plugin = []
|
||||
__plugin_mode = []
|
||||
__plugin_rt = []
|
||||
__rkyv = []
|
||||
ahash = ["dep:ahash"]
|
||||
concurrent = ["parking_lot"]
|
||||
debug = []
|
||||
default = []
|
||||
diagnostic-serde = []
|
||||
plugin-base = [
|
||||
"__plugin",
|
||||
"anyhow",
|
||||
"rkyv-impl",
|
||||
"diagnostic-serde",
|
||||
]
|
||||
plugin-mode = [
|
||||
"__plugin_mode",
|
||||
"plugin-base",
|
||||
]
|
||||
plugin-rt = [
|
||||
"__plugin_rt",
|
||||
"plugin-base",
|
||||
]
|
||||
plugin_transform_schema_v1 = []
|
||||
plugin_transform_schema_vtest = []
|
||||
rkyv-impl = [
|
||||
"__rkyv",
|
||||
"rkyv",
|
||||
"swc_atoms/rkyv-impl",
|
||||
"bytecheck",
|
||||
]
|
||||
tty-emitter = [
|
||||
"atty",
|
||||
"termcolor",
|
||||
]
|
||||
96
third-party/vendor/swc_common/benches/serde.rs
vendored
Normal file
96
third-party/vendor/swc_common/benches/serde.rs
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#![cfg_attr(not(feature = "serde-impl"), allow(unused))]
|
||||
|
||||
use ast_node::ast_node;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use swc_common::{Span, DUMMY_SP};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SerdeStr {
|
||||
span: Span,
|
||||
value: String,
|
||||
}
|
||||
|
||||
#[ast_node("String")]
|
||||
pub struct Str {
|
||||
span: Span,
|
||||
value: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct SerdeNum {
|
||||
span: Span,
|
||||
value: u64,
|
||||
}
|
||||
|
||||
#[ast_node("Number")]
|
||||
pub struct Num {
|
||||
span: Span,
|
||||
value: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
pub enum Serde {
|
||||
Number(SerdeNum),
|
||||
String(SerdeStr),
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
pub enum AstNode {
|
||||
#[tag("Number")]
|
||||
Number(Num),
|
||||
#[tag("String")]
|
||||
String(Str),
|
||||
}
|
||||
|
||||
fn bench_serde(c: &mut Criterion) {
|
||||
let src = Serde::String(SerdeStr {
|
||||
span: DUMMY_SP,
|
||||
value: String::from("perf-diff"),
|
||||
});
|
||||
|
||||
c.bench_function("serialization of serde", |b| {
|
||||
b.iter(|| black_box(serde_json::to_string(&src).unwrap()));
|
||||
});
|
||||
c.bench_function("deserialization of serde", |b| {
|
||||
let src = serde_json::to_string(&Serde::String(SerdeStr {
|
||||
span: DUMMY_SP,
|
||||
value: String::from("perf-diff"),
|
||||
}))
|
||||
.unwrap();
|
||||
println!("{}", src);
|
||||
|
||||
b.iter(|| black_box(serde_json::to_string(&src).unwrap()));
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_ast_node(c: &mut Criterion) {
|
||||
#[cfg(feature = "serde-impl")]
|
||||
c.bench_function("serialization of ast node", |b| {
|
||||
let src = AstNode::String(Str {
|
||||
span: DUMMY_SP,
|
||||
value: String::from("perf-diff"),
|
||||
});
|
||||
|
||||
b.iter(|| black_box(serde_json::to_string(&src).unwrap()));
|
||||
});
|
||||
#[cfg(feature = "serde-impl")]
|
||||
c.bench_function("deserialization of ast node", |b| {
|
||||
let src = serde_json::to_string(&AstNode::String(Str {
|
||||
span: DUMMY_SP,
|
||||
value: String::from("perf-diff"),
|
||||
}))
|
||||
.unwrap();
|
||||
println!("{}", src);
|
||||
|
||||
b.iter(|| {
|
||||
let t: AstNode = serde_json::from_str(&src).unwrap();
|
||||
|
||||
black_box(t);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_ast_node, bench_serde);
|
||||
criterion_main!(benches);
|
||||
31
third-party/vendor/swc_common/src/collections.rs
vendored
Normal file
31
third-party/vendor/swc_common/src/collections.rs
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#[cfg(feature = "ahash")]
|
||||
pub use self::ahash::*;
|
||||
#[cfg(not(feature = "ahash"))]
|
||||
pub use self::rustchash::*;
|
||||
|
||||
#[cfg(not(feature = "ahash"))]
|
||||
mod rustchash {
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
hash::BuildHasherDefault,
|
||||
};
|
||||
|
||||
use rustc_hash::FxHasher;
|
||||
|
||||
pub type ARandomState = BuildHasherDefault<FxHasher>;
|
||||
|
||||
pub type AHashMap<K, V> = HashMap<K, V, ARandomState>;
|
||||
|
||||
pub type AHashSet<V> = HashSet<V, ARandomState>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "ahash")]
|
||||
mod ahash {
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
pub type ARandomState = ahash::RandomState;
|
||||
|
||||
pub type AHashMap<K, V> = HashMap<K, V, ARandomState>;
|
||||
|
||||
pub type AHashSet<V> = HashSet<V, ARandomState>;
|
||||
}
|
||||
604
third-party/vendor/swc_common/src/comments.rs
vendored
Normal file
604
third-party/vendor/swc_common/src/comments.rs
vendored
Normal file
|
|
@ -0,0 +1,604 @@
|
|||
use std::{
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
use swc_atoms::{atom, Atom};
|
||||
|
||||
use crate::{
|
||||
pos::Spanned,
|
||||
syntax_pos::{BytePos, Span, DUMMY_SP},
|
||||
};
|
||||
|
||||
/// Stores comment.
|
||||
///
|
||||
/// ## Implementation notes
|
||||
///
|
||||
/// Methods uses `(&self)` instead of `(&mut self)` for some reasons. Firstly,
|
||||
/// this is similar to the previous api. Secondly, typescript parser requires
|
||||
/// backtracking, which requires [Clone]. To avoid cloning large vectors, we
|
||||
/// must use [Rc<RefCell<Comments>>]. We have two option. We may implement it in
|
||||
/// the parser or in the implementation. If we decide to go with first option,
|
||||
/// we should pass [Comments] to parser, and as a result we need another method
|
||||
/// to take comments back. If we decide to go with second way, we can just pass
|
||||
/// [&Comments] to the parser. Thirdly, `(&self)` allows multi-threaded
|
||||
/// use-cases such as swc itself.
|
||||
///
|
||||
/// We use [Option] instead of no-op Comments implementation to avoid allocation
|
||||
/// unless required.
|
||||
pub trait Comments {
|
||||
fn add_leading(&self, pos: BytePos, cmt: Comment);
|
||||
fn add_leading_comments(&self, pos: BytePos, comments: Vec<Comment>);
|
||||
fn has_leading(&self, pos: BytePos) -> bool;
|
||||
fn move_leading(&self, from: BytePos, to: BytePos);
|
||||
fn take_leading(&self, pos: BytePos) -> Option<Vec<Comment>>;
|
||||
fn get_leading(&self, pos: BytePos) -> Option<Vec<Comment>>;
|
||||
|
||||
fn add_trailing(&self, pos: BytePos, cmt: Comment);
|
||||
fn add_trailing_comments(&self, pos: BytePos, comments: Vec<Comment>);
|
||||
fn has_trailing(&self, pos: BytePos) -> bool;
|
||||
fn move_trailing(&self, from: BytePos, to: BytePos);
|
||||
fn take_trailing(&self, pos: BytePos) -> Option<Vec<Comment>>;
|
||||
fn get_trailing(&self, pos: BytePos) -> Option<Vec<Comment>>;
|
||||
|
||||
fn add_pure_comment(&self, pos: BytePos);
|
||||
|
||||
fn with_leading<F, Ret>(&self, pos: BytePos, f: F) -> Ret
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnOnce(&[Comment]) -> Ret,
|
||||
{
|
||||
let cmts = self.take_leading(pos);
|
||||
|
||||
let ret = if let Some(cmts) = &cmts {
|
||||
f(cmts)
|
||||
} else {
|
||||
f(&[])
|
||||
};
|
||||
|
||||
if let Some(cmts) = cmts {
|
||||
self.add_leading_comments(pos, cmts);
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
fn with_trailing<F, Ret>(&self, pos: BytePos, f: F) -> Ret
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnOnce(&[Comment]) -> Ret,
|
||||
{
|
||||
let cmts = self.take_trailing(pos);
|
||||
|
||||
let ret = if let Some(cmts) = &cmts {
|
||||
f(cmts)
|
||||
} else {
|
||||
f(&[])
|
||||
};
|
||||
|
||||
if let Some(cmts) = cmts {
|
||||
self.add_trailing_comments(pos, cmts);
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! delegate {
|
||||
() => {
|
||||
fn add_leading(&self, pos: BytePos, cmt: Comment) {
|
||||
(**self).add_leading(pos, cmt)
|
||||
}
|
||||
|
||||
fn add_leading_comments(&self, pos: BytePos, comments: Vec<Comment>) {
|
||||
(**self).add_leading_comments(pos, comments)
|
||||
}
|
||||
|
||||
fn has_leading(&self, pos: BytePos) -> bool {
|
||||
(**self).has_leading(pos)
|
||||
}
|
||||
|
||||
fn move_leading(&self, from: BytePos, to: BytePos) {
|
||||
(**self).move_leading(from, to)
|
||||
}
|
||||
|
||||
fn take_leading(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
(**self).take_leading(pos)
|
||||
}
|
||||
|
||||
fn get_leading(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
(**self).get_leading(pos)
|
||||
}
|
||||
|
||||
fn add_trailing(&self, pos: BytePos, cmt: Comment) {
|
||||
(**self).add_trailing(pos, cmt)
|
||||
}
|
||||
|
||||
fn add_trailing_comments(&self, pos: BytePos, comments: Vec<Comment>) {
|
||||
(**self).add_trailing_comments(pos, comments)
|
||||
}
|
||||
|
||||
fn has_trailing(&self, pos: BytePos) -> bool {
|
||||
(**self).has_trailing(pos)
|
||||
}
|
||||
|
||||
fn move_trailing(&self, from: BytePos, to: BytePos) {
|
||||
(**self).move_trailing(from, to)
|
||||
}
|
||||
|
||||
fn take_trailing(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
(**self).take_trailing(pos)
|
||||
}
|
||||
|
||||
fn get_trailing(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
(**self).get_trailing(pos)
|
||||
}
|
||||
|
||||
fn add_pure_comment(&self, pos: BytePos) {
|
||||
(**self).add_pure_comment(pos)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<T> Comments for &'_ T
|
||||
where
|
||||
T: ?Sized + Comments,
|
||||
{
|
||||
delegate!();
|
||||
}
|
||||
|
||||
impl<T> Comments for Arc<T>
|
||||
where
|
||||
T: ?Sized + Comments,
|
||||
{
|
||||
delegate!();
|
||||
}
|
||||
|
||||
impl<T> Comments for Rc<T>
|
||||
where
|
||||
T: ?Sized + Comments,
|
||||
{
|
||||
delegate!();
|
||||
}
|
||||
|
||||
impl<T> Comments for Box<T>
|
||||
where
|
||||
T: ?Sized + Comments,
|
||||
{
|
||||
delegate!();
|
||||
}
|
||||
|
||||
/// Implementation of [Comments] which does not store any comments.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
|
||||
pub struct NoopComments;
|
||||
|
||||
impl Comments for NoopComments {
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn add_leading(&self, _: BytePos, _: Comment) {}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn add_leading_comments(&self, _: BytePos, _: Vec<Comment>) {}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn has_leading(&self, _: BytePos) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn move_leading(&self, _: BytePos, _: BytePos) {}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn take_leading(&self, _: BytePos) -> Option<Vec<Comment>> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn get_leading(&self, _: BytePos) -> Option<Vec<Comment>> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn add_trailing(&self, _: BytePos, _: Comment) {}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn add_trailing_comments(&self, _: BytePos, _: Vec<Comment>) {}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn has_trailing(&self, _: BytePos) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn move_trailing(&self, _: BytePos, _: BytePos) {}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn take_trailing(&self, _: BytePos) -> Option<Vec<Comment>> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn get_trailing(&self, _: BytePos) -> Option<Vec<Comment>> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg_attr(not(debug_assertions), inline(always))]
|
||||
fn add_pure_comment(&self, _: BytePos) {}
|
||||
}
|
||||
|
||||
/// This implementation behaves like [NoopComments] if it's [None].
|
||||
impl<C> Comments for Option<C>
|
||||
where
|
||||
C: Comments,
|
||||
{
|
||||
fn add_leading(&self, pos: BytePos, cmt: Comment) {
|
||||
if let Some(c) = self {
|
||||
c.add_leading(pos, cmt)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_leading_comments(&self, pos: BytePos, comments: Vec<Comment>) {
|
||||
if let Some(c) = self {
|
||||
c.add_leading_comments(pos, comments)
|
||||
}
|
||||
}
|
||||
|
||||
fn has_leading(&self, pos: BytePos) -> bool {
|
||||
if let Some(c) = self {
|
||||
c.has_leading(pos)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn move_leading(&self, from: BytePos, to: BytePos) {
|
||||
if let Some(c) = self {
|
||||
c.move_leading(from, to)
|
||||
}
|
||||
}
|
||||
|
||||
fn take_leading(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
if let Some(c) = self {
|
||||
c.take_leading(pos)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_leading(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
if let Some(c) = self {
|
||||
c.get_leading(pos)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn add_trailing(&self, pos: BytePos, cmt: Comment) {
|
||||
if let Some(c) = self {
|
||||
c.add_trailing(pos, cmt)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_trailing_comments(&self, pos: BytePos, comments: Vec<Comment>) {
|
||||
if let Some(c) = self {
|
||||
c.add_trailing_comments(pos, comments)
|
||||
}
|
||||
}
|
||||
|
||||
fn has_trailing(&self, pos: BytePos) -> bool {
|
||||
if let Some(c) = self {
|
||||
c.has_trailing(pos)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn move_trailing(&self, from: BytePos, to: BytePos) {
|
||||
if let Some(c) = self {
|
||||
c.move_trailing(from, to)
|
||||
}
|
||||
}
|
||||
|
||||
fn take_trailing(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
if let Some(c) = self {
|
||||
c.take_trailing(pos)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn get_trailing(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
if let Some(c) = self {
|
||||
c.get_trailing(pos)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn add_pure_comment(&self, pos: BytePos) {
|
||||
if let Some(c) = self {
|
||||
c.add_pure_comment(pos)
|
||||
}
|
||||
}
|
||||
|
||||
fn with_leading<F, Ret>(&self, pos: BytePos, f: F) -> Ret
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnOnce(&[Comment]) -> Ret,
|
||||
{
|
||||
if let Some(c) = self {
|
||||
c.with_leading(pos, f)
|
||||
} else {
|
||||
f(&[])
|
||||
}
|
||||
}
|
||||
|
||||
fn with_trailing<F, Ret>(&self, pos: BytePos, f: F) -> Ret
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnOnce(&[Comment]) -> Ret,
|
||||
{
|
||||
if let Some(c) = self {
|
||||
c.with_trailing(pos, f)
|
||||
} else {
|
||||
f(&[])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type SingleThreadedCommentsMapInner = FxHashMap<BytePos, Vec<Comment>>;
|
||||
pub type SingleThreadedCommentsMap = Rc<RefCell<SingleThreadedCommentsMapInner>>;
|
||||
|
||||
/// Single-threaded storage for comments.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct SingleThreadedComments {
|
||||
leading: SingleThreadedCommentsMap,
|
||||
trailing: SingleThreadedCommentsMap,
|
||||
}
|
||||
|
||||
impl Comments for SingleThreadedComments {
|
||||
fn add_leading(&self, pos: BytePos, cmt: Comment) {
|
||||
self.leading.borrow_mut().entry(pos).or_default().push(cmt);
|
||||
}
|
||||
|
||||
fn add_leading_comments(&self, pos: BytePos, comments: Vec<Comment>) {
|
||||
self.leading
|
||||
.borrow_mut()
|
||||
.entry(pos)
|
||||
.or_default()
|
||||
.extend(comments);
|
||||
}
|
||||
|
||||
fn has_leading(&self, pos: BytePos) -> bool {
|
||||
if let Some(v) = self.leading.borrow().get(&pos) {
|
||||
!v.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn move_leading(&self, from: BytePos, to: BytePos) {
|
||||
let cmt = self.take_leading(from);
|
||||
|
||||
if let Some(mut cmt) = cmt {
|
||||
if from < to && self.has_leading(to) {
|
||||
cmt.extend(self.take_leading(to).unwrap());
|
||||
}
|
||||
|
||||
self.add_leading_comments(to, cmt);
|
||||
}
|
||||
}
|
||||
|
||||
fn take_leading(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
self.leading.borrow_mut().remove(&pos)
|
||||
}
|
||||
|
||||
fn get_leading(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
self.leading.borrow().get(&pos).map(|c| c.to_owned())
|
||||
}
|
||||
|
||||
fn add_trailing(&self, pos: BytePos, cmt: Comment) {
|
||||
self.trailing.borrow_mut().entry(pos).or_default().push(cmt);
|
||||
}
|
||||
|
||||
fn add_trailing_comments(&self, pos: BytePos, comments: Vec<Comment>) {
|
||||
self.trailing
|
||||
.borrow_mut()
|
||||
.entry(pos)
|
||||
.or_default()
|
||||
.extend(comments);
|
||||
}
|
||||
|
||||
fn has_trailing(&self, pos: BytePos) -> bool {
|
||||
if let Some(v) = self.trailing.borrow().get(&pos) {
|
||||
!v.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn move_trailing(&self, from: BytePos, to: BytePos) {
|
||||
let cmt = self.take_trailing(from);
|
||||
|
||||
if let Some(mut cmt) = cmt {
|
||||
if from < to && self.has_trailing(to) {
|
||||
cmt.extend(self.take_trailing(to).unwrap());
|
||||
}
|
||||
|
||||
self.add_trailing_comments(to, cmt);
|
||||
}
|
||||
}
|
||||
|
||||
fn take_trailing(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
self.trailing.borrow_mut().remove(&pos)
|
||||
}
|
||||
|
||||
fn get_trailing(&self, pos: BytePos) -> Option<Vec<Comment>> {
|
||||
self.trailing.borrow().get(&pos).map(|c| c.to_owned())
|
||||
}
|
||||
|
||||
fn add_pure_comment(&self, pos: BytePos) {
|
||||
let mut leading_map = self.leading.borrow_mut();
|
||||
let leading = leading_map.entry(pos).or_default();
|
||||
let pure_comment = Comment {
|
||||
kind: CommentKind::Block,
|
||||
span: DUMMY_SP,
|
||||
text: atom!("#__PURE__"),
|
||||
};
|
||||
|
||||
if !leading.iter().any(|c| c.text == pure_comment.text) {
|
||||
leading.push(pure_comment);
|
||||
}
|
||||
}
|
||||
|
||||
fn with_leading<F, Ret>(&self, pos: BytePos, f: F) -> Ret
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnOnce(&[Comment]) -> Ret,
|
||||
{
|
||||
let b = self.leading.borrow();
|
||||
let cmts = b.get(&pos);
|
||||
|
||||
if let Some(cmts) = &cmts {
|
||||
f(cmts)
|
||||
} else {
|
||||
f(&[])
|
||||
}
|
||||
}
|
||||
|
||||
fn with_trailing<F, Ret>(&self, pos: BytePos, f: F) -> Ret
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnOnce(&[Comment]) -> Ret,
|
||||
{
|
||||
let b = self.trailing.borrow();
|
||||
let cmts = b.get(&pos);
|
||||
|
||||
if let Some(cmts) = &cmts {
|
||||
f(cmts)
|
||||
} else {
|
||||
f(&[])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SingleThreadedComments {
|
||||
/// Creates a new `SingleThreadedComments` from the provided leading and
|
||||
/// trailing.
|
||||
pub fn from_leading_and_trailing(
|
||||
leading: SingleThreadedCommentsMap,
|
||||
trailing: SingleThreadedCommentsMap,
|
||||
) -> Self {
|
||||
SingleThreadedComments { leading, trailing }
|
||||
}
|
||||
|
||||
/// Takes all the comments as (leading, trailing).
|
||||
pub fn take_all(self) -> (SingleThreadedCommentsMap, SingleThreadedCommentsMap) {
|
||||
(self.leading, self.trailing)
|
||||
}
|
||||
|
||||
/// Borrows all the comments as (leading, trailing).
|
||||
pub fn borrow_all(
|
||||
&self,
|
||||
) -> (
|
||||
Ref<SingleThreadedCommentsMapInner>,
|
||||
Ref<SingleThreadedCommentsMapInner>,
|
||||
) {
|
||||
(self.leading.borrow(), self.trailing.borrow())
|
||||
}
|
||||
|
||||
/// Borrows all the comments as (leading, trailing).
|
||||
pub fn borrow_all_mut(
|
||||
&self,
|
||||
) -> (
|
||||
RefMut<SingleThreadedCommentsMapInner>,
|
||||
RefMut<SingleThreadedCommentsMapInner>,
|
||||
) {
|
||||
(self.leading.borrow_mut(), self.trailing.borrow_mut())
|
||||
}
|
||||
|
||||
pub fn with_leading<F, Ret>(&self, pos: BytePos, op: F) -> Ret
|
||||
where
|
||||
F: FnOnce(&[Comment]) -> Ret,
|
||||
{
|
||||
if let Some(comments) = self.leading.borrow().get(&pos) {
|
||||
op(comments)
|
||||
} else {
|
||||
op(&[])
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_trailing<F, Ret>(&self, pos: BytePos, op: F) -> Ret
|
||||
where
|
||||
F: FnOnce(&[Comment]) -> Ret,
|
||||
{
|
||||
if let Some(comments) = self.trailing.borrow().get(&pos) {
|
||||
op(comments)
|
||||
} else {
|
||||
op(&[])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct Comment {
|
||||
pub kind: CommentKind,
|
||||
pub span: Span,
|
||||
/// [`Atom::new_bad`][] is perfectly fine for this value.
|
||||
pub text: Atom,
|
||||
}
|
||||
|
||||
impl Spanned for Comment {
|
||||
fn span(&self) -> Span {
|
||||
self.span
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
pub enum CommentKind {
|
||||
Line,
|
||||
Block,
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "0.13.5",
|
||||
note = "helper methods are merged into Comments itself"
|
||||
)]
|
||||
pub trait CommentsExt: Comments {
|
||||
fn with_leading<F, Ret>(&self, pos: BytePos, op: F) -> Ret
|
||||
where
|
||||
F: FnOnce(&[Comment]) -> Ret,
|
||||
{
|
||||
if let Some(comments) = self.get_leading(pos) {
|
||||
op(&comments)
|
||||
} else {
|
||||
op(&[])
|
||||
}
|
||||
}
|
||||
|
||||
fn with_trailing<F, Ret>(&self, pos: BytePos, op: F) -> Ret
|
||||
where
|
||||
F: FnOnce(&[Comment]) -> Ret,
|
||||
{
|
||||
if let Some(comments) = self.get_trailing(pos) {
|
||||
op(&comments)
|
||||
} else {
|
||||
op(&[])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<C> CommentsExt for C where C: Comments {}
|
||||
302
third-party/vendor/swc_common/src/eq.rs
vendored
Normal file
302
third-party/vendor/swc_common/src/eq.rs
vendored
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
use std::{cell::RefCell, cmp::PartialEq, rc::Rc, sync::Arc};
|
||||
|
||||
use num_bigint::BigInt;
|
||||
use string_cache::Atom;
|
||||
|
||||
use crate::{BytePos, Span, SyntaxContext};
|
||||
|
||||
/// Derive with `#[derive(EqIgnoreSpan)]`.
|
||||
pub trait EqIgnoreSpan {
|
||||
fn eq_ignore_span(&self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
impl EqIgnoreSpan for Span {
|
||||
/// Always returns true
|
||||
#[inline]
|
||||
fn eq_ignore_span(&self, _: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl EqIgnoreSpan for swc_atoms::Atom {
|
||||
#[inline]
|
||||
fn eq_ignore_span(&self, r: &Self) -> bool {
|
||||
self == r
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> EqIgnoreSpan for [T]
|
||||
where
|
||||
T: EqIgnoreSpan,
|
||||
{
|
||||
fn eq_ignore_span(&self, other: &Self) -> bool {
|
||||
self.len() == other.len()
|
||||
&& self
|
||||
.iter()
|
||||
.zip(other.iter())
|
||||
.all(|(a, b)| a.eq_ignore_span(b))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> EqIgnoreSpan for Option<T>
|
||||
where
|
||||
T: EqIgnoreSpan,
|
||||
{
|
||||
fn eq_ignore_span(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Some(l), Some(r)) => l.eq_ignore_span(r),
|
||||
(None, None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> EqIgnoreSpan for Vec<T>
|
||||
where
|
||||
T: EqIgnoreSpan,
|
||||
{
|
||||
fn eq_ignore_span(&self, other: &Self) -> bool {
|
||||
self.len() == other.len()
|
||||
&& self
|
||||
.iter()
|
||||
.zip(other.iter())
|
||||
.all(|(a, b)| a.eq_ignore_span(b))
|
||||
}
|
||||
}
|
||||
|
||||
/// Derive with `#[derive(TypeEq)]`.
|
||||
pub trait TypeEq {
|
||||
/// **Note**: This method should return `true` for non-type values.
|
||||
fn type_eq(&self, other: &Self) -> bool;
|
||||
}
|
||||
|
||||
impl TypeEq for Span {
|
||||
/// Always returns true
|
||||
#[inline]
|
||||
fn type_eq(&self, _: &Self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TypeEq for Option<T>
|
||||
where
|
||||
T: TypeEq,
|
||||
{
|
||||
fn type_eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Some(l), Some(r)) => l.type_eq(r),
|
||||
(None, None) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TypeEq for Vec<T>
|
||||
where
|
||||
T: TypeEq,
|
||||
{
|
||||
fn type_eq(&self, other: &Self) -> bool {
|
||||
self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a.type_eq(b))
|
||||
}
|
||||
}
|
||||
|
||||
/// Implement traits using PartialEq
|
||||
macro_rules! eq {
|
||||
($T:ty) => {
|
||||
impl EqIgnoreSpan for $T {
|
||||
#[inline]
|
||||
fn eq_ignore_span(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeEq for $T {
|
||||
#[inline]
|
||||
fn type_eq(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(
|
||||
$(
|
||||
$T:ty
|
||||
),*
|
||||
) => {
|
||||
$(
|
||||
eq!($T);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
eq!(SyntaxContext, BytePos);
|
||||
eq!(bool);
|
||||
eq!(usize, u8, u16, u32, u64, u128);
|
||||
eq!(isize, i8, i16, i32, i64, i128);
|
||||
eq!(f32, f64);
|
||||
eq!(char, str, String);
|
||||
|
||||
impl<S: PartialEq> EqIgnoreSpan for Atom<S> {
|
||||
#[inline]
|
||||
fn eq_ignore_span(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: PartialEq> TypeEq for Atom<S> {
|
||||
#[inline]
|
||||
fn type_eq(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! deref {
|
||||
($T:ident) => {
|
||||
impl<N> EqIgnoreSpan for $T<N>
|
||||
where
|
||||
N: EqIgnoreSpan,
|
||||
{
|
||||
#[inline]
|
||||
fn eq_ignore_span(&self, other: &Self) -> bool {
|
||||
(**self).eq_ignore_span(&**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N> TypeEq for $T<N>
|
||||
where
|
||||
N: TypeEq,
|
||||
{
|
||||
#[inline]
|
||||
fn type_eq(&self, other: &Self) -> bool {
|
||||
(**self).type_eq(&**other)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
(
|
||||
$(
|
||||
$T:ident
|
||||
),*
|
||||
) => {
|
||||
$(
|
||||
deref!($T);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
deref!(Box, Rc, Arc);
|
||||
|
||||
impl<'a, N> EqIgnoreSpan for &'a N
|
||||
where
|
||||
N: EqIgnoreSpan,
|
||||
{
|
||||
#[inline]
|
||||
fn eq_ignore_span(&self, other: &Self) -> bool {
|
||||
(**self).eq_ignore_span(&**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, N> TypeEq for &'a N
|
||||
where
|
||||
N: TypeEq,
|
||||
{
|
||||
#[inline]
|
||||
fn type_eq(&self, other: &Self) -> bool {
|
||||
(**self).type_eq(&**other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<N> EqIgnoreSpan for RefCell<N>
|
||||
where
|
||||
N: EqIgnoreSpan,
|
||||
{
|
||||
fn eq_ignore_span(&self, other: &Self) -> bool {
|
||||
self.borrow().eq_ignore_span(&*other.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
impl<N> TypeEq for RefCell<N>
|
||||
where
|
||||
N: TypeEq,
|
||||
{
|
||||
fn type_eq(&self, other: &Self) -> bool {
|
||||
self.borrow().type_eq(&*other.borrow())
|
||||
}
|
||||
}
|
||||
|
||||
impl EqIgnoreSpan for BigInt {
|
||||
fn eq_ignore_span(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
impl TypeEq for BigInt {
|
||||
fn type_eq(&self, other: &Self) -> bool {
|
||||
self == other
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! tuple {
|
||||
(
|
||||
$num:tt: $F:ident
|
||||
) => {};
|
||||
|
||||
|
||||
(
|
||||
$first:tt: $F:ident,
|
||||
$(
|
||||
$num:tt: $N:ident
|
||||
),*
|
||||
) =>{
|
||||
tuple!($($num: $N),*);
|
||||
|
||||
impl<$F: EqIgnoreSpan, $($N: EqIgnoreSpan),*> EqIgnoreSpan for ($F, $($N,)*) {
|
||||
fn eq_ignore_span(&self,rhs: &Self) -> bool {
|
||||
self.$first.eq_ignore_span(&rhs.$first) &&
|
||||
$(
|
||||
self.$num.eq_ignore_span(&rhs.$num)
|
||||
)
|
||||
&& *
|
||||
}
|
||||
}
|
||||
|
||||
impl<$F: TypeEq, $($N: TypeEq),*> TypeEq for ($F, $($N,)*) {
|
||||
fn type_eq(&self,rhs: &Self) -> bool {
|
||||
self.$first.type_eq(&rhs.$first) &&
|
||||
$(
|
||||
self.$num.type_eq(&rhs.$num)
|
||||
)
|
||||
&& *
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
tuple!(
|
||||
25: Z,
|
||||
24: Y,
|
||||
23: X,
|
||||
22: W,
|
||||
21: V,
|
||||
20: U,
|
||||
19: T,
|
||||
18: S,
|
||||
17: R,
|
||||
16: Q,
|
||||
15: P,
|
||||
14: O,
|
||||
13: N,
|
||||
12: M,
|
||||
11: L,
|
||||
10: K,
|
||||
9: J,
|
||||
8: I,
|
||||
7: H,
|
||||
6: G,
|
||||
5: F,
|
||||
4: E,
|
||||
3: D,
|
||||
2: C,
|
||||
1: B,
|
||||
0: A
|
||||
);
|
||||
510
third-party/vendor/swc_common/src/errors/diagnostic.rs
vendored
Normal file
510
third-party/vendor/swc_common/src/errors/diagnostic.rs
vendored
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use super::{snippet::Style, Applicability, CodeSuggestion, Level, Substitution, SubstitutionPart};
|
||||
use crate::syntax_pos::{MultiSpan, Span};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct Message(pub String, pub Style);
|
||||
|
||||
#[must_use]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct Diagnostic {
|
||||
pub level: Level,
|
||||
pub message: Vec<Message>,
|
||||
pub code: Option<DiagnosticId>,
|
||||
pub span: MultiSpan,
|
||||
pub children: Vec<SubDiagnostic>,
|
||||
pub suggestions: Vec<CodeSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(u32)))]
|
||||
pub enum DiagnosticId {
|
||||
Error(String),
|
||||
Lint(String),
|
||||
}
|
||||
|
||||
/// For example a note attached to an error.
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct SubDiagnostic {
|
||||
pub level: Level,
|
||||
pub message: Vec<Message>,
|
||||
pub span: MultiSpan,
|
||||
pub render_span: Option<MultiSpan>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Default)]
|
||||
pub struct DiagnosticStyledString(pub Vec<StringPart>);
|
||||
|
||||
impl DiagnosticStyledString {
|
||||
pub fn new() -> DiagnosticStyledString {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn push_normal<S: Into<String>>(&mut self, t: S) {
|
||||
self.0.push(StringPart::Normal(t.into()));
|
||||
}
|
||||
|
||||
pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
|
||||
self.0.push(StringPart::Highlighted(t.into()));
|
||||
}
|
||||
|
||||
pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
|
||||
DiagnosticStyledString(vec![StringPart::Normal(t.into())])
|
||||
}
|
||||
|
||||
pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
|
||||
DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
|
||||
}
|
||||
|
||||
pub fn content(&self) -> String {
|
||||
self.0.iter().map(|x| x.content()).collect::<String>()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum StringPart {
|
||||
Normal(String),
|
||||
Highlighted(String),
|
||||
}
|
||||
|
||||
impl StringPart {
|
||||
pub fn content(&self) -> &str {
|
||||
match self {
|
||||
&StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Diagnostic {
|
||||
pub fn new(level: Level, message: &str) -> Self {
|
||||
Diagnostic::new_with_code(level, None, message)
|
||||
}
|
||||
|
||||
pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
|
||||
Diagnostic {
|
||||
level,
|
||||
message: vec![Message(message.to_owned(), Style::NoStyle)],
|
||||
code,
|
||||
span: MultiSpan::new(),
|
||||
children: vec![],
|
||||
suggestions: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_error(&self) -> bool {
|
||||
match self.level {
|
||||
Level::Bug | Level::Fatal | Level::PhaseFatal | Level::Error | Level::FailureNote => {
|
||||
true
|
||||
}
|
||||
|
||||
Level::Warning | Level::Note | Level::Help | Level::Cancelled => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Cancel the diagnostic (a structured diagnostic must either be emitted or
|
||||
/// canceled or it will panic when dropped).
|
||||
pub fn cancel(&mut self) {
|
||||
self.level = Level::Cancelled;
|
||||
}
|
||||
|
||||
pub fn cancelled(&self) -> bool {
|
||||
self.level == Level::Cancelled
|
||||
}
|
||||
|
||||
/// Add a span/label to be included in the resulting snippet.
|
||||
/// This is pushed onto the `MultiSpan` that was created when the
|
||||
/// diagnostic was first built. If you don't call this function at
|
||||
/// all, and you just supplied a `Span` to create the diagnostic,
|
||||
/// then the snippet will just include that `Span`, which is
|
||||
/// called the primary span.
|
||||
pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
|
||||
self.span.push_span_label(span, label.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
|
||||
let before = self.span.clone();
|
||||
self.set_span(after);
|
||||
for span_label in before.span_labels() {
|
||||
if let Some(label) = span_label.label {
|
||||
self.span_label(after, label);
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn note_expected_found(
|
||||
&mut self,
|
||||
label: &dyn fmt::Display,
|
||||
expected: DiagnosticStyledString,
|
||||
found: DiagnosticStyledString,
|
||||
) -> &mut Self {
|
||||
self.note_expected_found_extra(label, expected, found, &"", &"")
|
||||
}
|
||||
|
||||
pub fn note_expected_found_extra(
|
||||
&mut self,
|
||||
label: &dyn fmt::Display,
|
||||
expected: DiagnosticStyledString,
|
||||
found: DiagnosticStyledString,
|
||||
expected_extra: &dyn fmt::Display,
|
||||
found_extra: &dyn fmt::Display,
|
||||
) -> &mut Self {
|
||||
let mut msg: Vec<_> = vec![Message(format!("expected {} `", label), Style::NoStyle)];
|
||||
msg.extend(expected.0.iter().map(|x| match *x {
|
||||
StringPart::Normal(ref s) => Message(s.to_owned(), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => Message(s.to_owned(), Style::Highlight),
|
||||
}));
|
||||
msg.push(Message(format!("`{}\n", expected_extra), Style::NoStyle));
|
||||
msg.push(Message(format!(" found {} `", label), Style::NoStyle));
|
||||
msg.extend(found.0.iter().map(|x| match *x {
|
||||
StringPart::Normal(ref s) => Message(s.to_owned(), Style::NoStyle),
|
||||
StringPart::Highlighted(ref s) => Message(s.to_owned(), Style::Highlight),
|
||||
}));
|
||||
msg.push(Message(format!("`{}", found_extra), Style::NoStyle));
|
||||
|
||||
// For now, just attach these as notes
|
||||
self.highlighted_note(msg);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
|
||||
self.highlighted_note(vec![
|
||||
Message(format!("`{}` from trait: `", name), Style::NoStyle),
|
||||
Message(signature, Style::Highlight),
|
||||
Message("`".to_string(), Style::NoStyle),
|
||||
]);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn note(&mut self, msg: &str) -> &mut Self {
|
||||
self.sub(Level::Note, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn highlighted_note(&mut self, msg: Vec<Message>) -> &mut Self {
|
||||
self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn span_note<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
|
||||
self.sub(Level::Note, msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn warn(&mut self, msg: &str) -> &mut Self {
|
||||
self.sub(Level::Warning, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
|
||||
self.sub(Level::Warning, msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn help(&mut self, msg: &str) -> &mut Self {
|
||||
self.sub(Level::Help, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn span_help<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self {
|
||||
self.sub(Level::Help, msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
|
||||
/// Prints out a message with a suggested edit of the code. If the
|
||||
/// suggestion is presented inline it will only show the text message
|
||||
/// and not the text.
|
||||
///
|
||||
/// See `CodeSuggestion` for more information.
|
||||
#[deprecated(note = "Use `span_suggestion_short_with_applicability`")]
|
||||
pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
|
||||
self.suggestions.push(CodeSuggestion {
|
||||
substitutions: vec![Substitution {
|
||||
parts: vec![SubstitutionPart {
|
||||
snippet: suggestion,
|
||||
span: sp,
|
||||
}],
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: false,
|
||||
applicability: Applicability::Unspecified,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Prints out a message with a suggested edit of the code.
|
||||
///
|
||||
/// In case of short messages and a simple suggestion,
|
||||
/// rustc displays it as a label like
|
||||
///
|
||||
/// "try adding parentheses: `(tup.0).1`"
|
||||
///
|
||||
/// The message
|
||||
///
|
||||
/// * should not end in any punctuation (a `:` is added automatically)
|
||||
/// * should not be a question
|
||||
/// * should not contain any parts like "the following", "as shown"
|
||||
/// * may look like "to do xyz, use" or "to do xyz, use abc"
|
||||
/// * may contain a name of a function, variable or type, but not whole
|
||||
/// expressions
|
||||
///
|
||||
/// See `CodeSuggestion` for more information.
|
||||
#[deprecated(note = "Use `span_suggestion_with_applicability`")]
|
||||
pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
|
||||
self.suggestions.push(CodeSuggestion {
|
||||
substitutions: vec![Substitution {
|
||||
parts: vec![SubstitutionPart {
|
||||
snippet: suggestion,
|
||||
span: sp,
|
||||
}],
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: true,
|
||||
applicability: Applicability::Unspecified,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn multipart_suggestion_with_applicability(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
self.suggestions.push(CodeSuggestion {
|
||||
substitutions: vec![Substitution {
|
||||
parts: suggestion
|
||||
.into_iter()
|
||||
.map(|(span, snippet)| SubstitutionPart { snippet, span })
|
||||
.collect(),
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: true,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
#[deprecated(note = "Use `multipart_suggestion_with_applicability`")]
|
||||
pub fn multipart_suggestion(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
) -> &mut Self {
|
||||
self.multipart_suggestion_with_applicability(msg, suggestion, Applicability::Unspecified)
|
||||
}
|
||||
|
||||
/// Prints out a message with multiple suggested edits of the code.
|
||||
#[deprecated(note = "Use `span_suggestions_with_applicability`")]
|
||||
pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
|
||||
self.suggestions.push(CodeSuggestion {
|
||||
substitutions: suggestions
|
||||
.into_iter()
|
||||
.map(|snippet| Substitution {
|
||||
parts: vec![SubstitutionPart { snippet, span: sp }],
|
||||
})
|
||||
.collect(),
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: true,
|
||||
applicability: Applicability::Unspecified,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// This is a suggestion that may contain mistakes or fillers and should
|
||||
/// be read and understood by a human.
|
||||
pub fn span_suggestion_with_applicability(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
self.suggestions.push(CodeSuggestion {
|
||||
substitutions: vec![Substitution {
|
||||
parts: vec![SubstitutionPart {
|
||||
snippet: suggestion,
|
||||
span: sp,
|
||||
}],
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: true,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn span_suggestions_with_applicability(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestions: impl Iterator<Item = String>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
self.suggestions.push(CodeSuggestion {
|
||||
substitutions: suggestions
|
||||
.map(|snippet| Substitution {
|
||||
parts: vec![SubstitutionPart { snippet, span: sp }],
|
||||
})
|
||||
.collect(),
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: true,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn span_suggestion_short_with_applicability(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
self.suggestions.push(CodeSuggestion {
|
||||
substitutions: vec![Substitution {
|
||||
parts: vec![SubstitutionPart {
|
||||
snippet: suggestion,
|
||||
span: sp,
|
||||
}],
|
||||
}],
|
||||
msg: msg.to_owned(),
|
||||
show_code_when_inline: false,
|
||||
applicability,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
|
||||
self.span = sp.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
|
||||
self.code = Some(s);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_code(&self) -> Option<DiagnosticId> {
|
||||
self.code.clone()
|
||||
}
|
||||
|
||||
pub fn message(&self) -> String {
|
||||
self.message
|
||||
.iter()
|
||||
.map(|i| i.0.as_str())
|
||||
.collect::<String>()
|
||||
}
|
||||
|
||||
pub fn styled_message(&self) -> &Vec<Message> {
|
||||
&self.message
|
||||
}
|
||||
|
||||
/// Used by a lint. Copies over all details *but* the "main
|
||||
/// message".
|
||||
pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
|
||||
self.span = from.span.clone();
|
||||
self.code = from.code.clone();
|
||||
self.children.extend(from.children.iter().cloned())
|
||||
}
|
||||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// public methods above.
|
||||
pub fn sub(
|
||||
&mut self,
|
||||
level: Level,
|
||||
message: &str,
|
||||
span: MultiSpan,
|
||||
render_span: Option<MultiSpan>,
|
||||
) {
|
||||
let sub = SubDiagnostic {
|
||||
level,
|
||||
message: vec![Message(message.to_owned(), Style::NoStyle)],
|
||||
span,
|
||||
render_span,
|
||||
};
|
||||
self.children.push(sub);
|
||||
}
|
||||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// public methods above.
|
||||
fn sub_with_highlights(
|
||||
&mut self,
|
||||
level: Level,
|
||||
message: Vec<Message>,
|
||||
span: MultiSpan,
|
||||
render_span: Option<MultiSpan>,
|
||||
) {
|
||||
let sub = SubDiagnostic {
|
||||
level,
|
||||
message,
|
||||
span,
|
||||
render_span,
|
||||
};
|
||||
self.children.push(sub);
|
||||
}
|
||||
}
|
||||
|
||||
impl SubDiagnostic {
|
||||
pub fn message(&self) -> String {
|
||||
self.message
|
||||
.iter()
|
||||
.map(|i| i.0.as_str())
|
||||
.collect::<String>()
|
||||
}
|
||||
|
||||
pub fn styled_message(&self) -> &Vec<Message> {
|
||||
&self.message
|
||||
}
|
||||
}
|
||||
348
third-party/vendor/swc_common/src/errors/diagnostic_builder.rs
vendored
Normal file
348
third-party/vendor/swc_common/src/errors/diagnostic_builder.rs
vendored
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
ops::{Deref, DerefMut},
|
||||
thread::panicking,
|
||||
};
|
||||
|
||||
use tracing::debug;
|
||||
|
||||
use super::{Applicability, Diagnostic, DiagnosticId, DiagnosticStyledString, Handler, Level};
|
||||
use crate::syntax_pos::{MultiSpan, Span};
|
||||
|
||||
/// Used for emitting structured error messages and other diagnostic
|
||||
/// information.
|
||||
///
|
||||
/// If there is some state in a downstream crate you would like to
|
||||
/// access in the methods of `DiagnosticBuilder` here, consider
|
||||
/// extending `HandlerFlags`, accessed via `self.handler.flags`.
|
||||
#[must_use]
|
||||
#[derive(Clone)]
|
||||
pub struct DiagnosticBuilder<'a> {
|
||||
pub handler: &'a Handler,
|
||||
#[cfg(not(feature = "__plugin_mode"))]
|
||||
pub(crate) diagnostic: Box<Diagnostic>,
|
||||
#[cfg(feature = "__plugin_mode")]
|
||||
pub diagnostic: Box<Diagnostic>,
|
||||
allow_suggestions: bool,
|
||||
}
|
||||
|
||||
/// In general, the `DiagnosticBuilder` uses deref to allow access to
|
||||
/// the fields and methods of the embedded `diagnostic` in a
|
||||
/// transparent way. *However,* many of the methods are intended to
|
||||
/// be used in a chained way, and hence ought to return `self`. In
|
||||
/// that case, we can't just naively forward to the method on the
|
||||
/// `diagnostic`, because the return type would be a `&Diagnostic`
|
||||
/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
|
||||
/// it easy to declare such methods on the builder.
|
||||
#[allow(unused)]
|
||||
macro_rules! forward {
|
||||
// Forward pattern for &self -> &Self
|
||||
(pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self) => {
|
||||
pub fn $n(&self, $($name: $ty),*) -> &Self {
|
||||
#[allow(deprecated)]
|
||||
self.diagnostic.$n($($name),*);
|
||||
self
|
||||
}
|
||||
};
|
||||
|
||||
// Forward pattern for &mut self -> &mut Self
|
||||
(pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self) => {
|
||||
pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
|
||||
#[allow(deprecated)]
|
||||
self.diagnostic.$n($($name),*);
|
||||
self
|
||||
}
|
||||
};
|
||||
|
||||
// Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
|
||||
// type parameter. No obvious way to make this more generic.
|
||||
(pub fn $n:ident<S: Into<MultiSpan>>(
|
||||
&mut self,
|
||||
$($name:ident: $ty:ty),*
|
||||
$(,)*) -> &mut Self) => {
|
||||
pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
|
||||
#[allow(deprecated)]
|
||||
self.diagnostic.$n($($name),*);
|
||||
self
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<'a> Deref for DiagnosticBuilder<'a> {
|
||||
type Target = Diagnostic;
|
||||
|
||||
fn deref(&self) -> &Diagnostic {
|
||||
&self.diagnostic
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DerefMut for DiagnosticBuilder<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Diagnostic {
|
||||
&mut self.diagnostic
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DiagnosticBuilder<'a> {
|
||||
forward!(pub fn note_expected_found(&mut self,
|
||||
label: &dyn fmt::Display,
|
||||
expected: DiagnosticStyledString,
|
||||
found: DiagnosticStyledString,
|
||||
) -> &mut Self);
|
||||
|
||||
forward!(pub fn note_expected_found_extra(&mut self,
|
||||
label: &dyn fmt::Display,
|
||||
expected: DiagnosticStyledString,
|
||||
found: DiagnosticStyledString,
|
||||
expected_extra: &dyn fmt::Display,
|
||||
found_extra: &dyn fmt::Display,
|
||||
) -> &mut Self);
|
||||
|
||||
forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
|
||||
|
||||
forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
) -> &mut Self);
|
||||
|
||||
forward!(pub fn warn(&mut self, msg: &str) -> &mut Self);
|
||||
|
||||
forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self);
|
||||
|
||||
forward!(pub fn help(&mut self , msg: &str) -> &mut Self);
|
||||
|
||||
forward!(pub fn span_help<S: Into<MultiSpan>>(&mut self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
) -> &mut Self);
|
||||
|
||||
forward!(pub fn span_suggestion_short(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestion: String,
|
||||
) -> &mut Self);
|
||||
|
||||
forward!(pub fn multipart_suggestion(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
) -> &mut Self);
|
||||
|
||||
forward!(pub fn span_suggestion(&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestion: String,
|
||||
) -> &mut Self);
|
||||
|
||||
forward!(pub fn span_suggestions(&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestions: Vec<String>,
|
||||
) -> &mut Self);
|
||||
|
||||
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
|
||||
|
||||
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
|
||||
|
||||
/// Emit the diagnostic.
|
||||
pub fn emit(&mut self) {
|
||||
if self.cancelled() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.handler.emit_db(self);
|
||||
self.cancel();
|
||||
}
|
||||
|
||||
/// Buffers the diagnostic for later emission, unless handler
|
||||
/// has disabled such buffering.
|
||||
pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) {
|
||||
if self.handler.flags.dont_buffer_diagnostics || self.handler.flags.treat_err_as_bug {
|
||||
self.emit();
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to use `ptr::read` because `DiagnosticBuilder`
|
||||
// implements `Drop`.
|
||||
let diagnostic;
|
||||
unsafe {
|
||||
diagnostic = ::std::ptr::read(&self.diagnostic);
|
||||
::std::mem::forget(self);
|
||||
};
|
||||
// Logging here is useful to help track down where in logs an error was
|
||||
// actually emitted.
|
||||
if cfg!(feature = "debug") {
|
||||
debug!("buffer: diagnostic={:?}", diagnostic);
|
||||
}
|
||||
buffered_diagnostics.push(*diagnostic);
|
||||
}
|
||||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// span_* methods instead.
|
||||
pub fn sub<S: Into<MultiSpan>>(
|
||||
&mut self,
|
||||
level: Level,
|
||||
message: &str,
|
||||
span: Option<S>,
|
||||
) -> &mut Self {
|
||||
let span = span.map(|s| s.into()).unwrap_or_else(MultiSpan::new);
|
||||
self.diagnostic.sub(level, message, span, None);
|
||||
self
|
||||
}
|
||||
|
||||
/// Delay emission of this diagnostic as a bug.
|
||||
///
|
||||
/// This can be useful in contexts where an error indicates a bug but
|
||||
/// typically this only happens when other compilation errors have already
|
||||
/// happened. In those cases this can be used to defer emission of this
|
||||
/// diagnostic as a bug in the compiler only if no other errors have been
|
||||
/// emitted.
|
||||
///
|
||||
/// In the meantime, though, callsites are required to deal with the "bug"
|
||||
/// locally in whichever way makes the most sense.
|
||||
pub fn delay_as_bug(&mut self) {
|
||||
self.level = Level::Bug;
|
||||
self.handler.delay_as_bug(*self.diagnostic.clone());
|
||||
self.cancel();
|
||||
}
|
||||
|
||||
/// Add a span/label to be included in the resulting snippet.
|
||||
/// This is pushed onto the `MultiSpan` that was created when the
|
||||
/// diagnostic was first built. If you don't call this function at
|
||||
/// all, and you just supplied a `Span` to create the diagnostic,
|
||||
/// then the snippet will just include that `Span`, which is
|
||||
/// called the primary span.
|
||||
pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
|
||||
self.diagnostic.span_label(span, label);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn multipart_suggestion_with_applicability(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
suggestion: Vec<(Span, String)>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
if !self.allow_suggestions {
|
||||
return self;
|
||||
}
|
||||
self.diagnostic
|
||||
.multipart_suggestion_with_applicability(msg, suggestion, applicability);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn span_suggestion_with_applicability(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
if !self.allow_suggestions {
|
||||
return self;
|
||||
}
|
||||
self.diagnostic
|
||||
.span_suggestion_with_applicability(sp, msg, suggestion, applicability);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn span_suggestions_with_applicability(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestions: impl Iterator<Item = String>,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
if !self.allow_suggestions {
|
||||
return self;
|
||||
}
|
||||
self.diagnostic
|
||||
.span_suggestions_with_applicability(sp, msg, suggestions, applicability);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn span_suggestion_short_with_applicability(
|
||||
&mut self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
suggestion: String,
|
||||
applicability: Applicability,
|
||||
) -> &mut Self {
|
||||
if !self.allow_suggestions {
|
||||
return self;
|
||||
}
|
||||
self.diagnostic.span_suggestion_short_with_applicability(
|
||||
sp,
|
||||
msg,
|
||||
suggestion,
|
||||
applicability,
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn allow_suggestions(&mut self, allow: bool) -> &mut Self {
|
||||
self.allow_suggestions = allow;
|
||||
self
|
||||
}
|
||||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// struct_* methods on Handler.
|
||||
pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> {
|
||||
DiagnosticBuilder::new_with_code(handler, level, None, message)
|
||||
}
|
||||
|
||||
/// Convenience function for internal use, clients should use one of the
|
||||
/// struct_* methods on Handler.
|
||||
pub fn new_with_code(
|
||||
handler: &'a Handler,
|
||||
level: Level,
|
||||
code: Option<DiagnosticId>,
|
||||
message: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let diagnostic = Diagnostic::new_with_code(level, code, message);
|
||||
DiagnosticBuilder::new_diagnostic(handler, diagnostic)
|
||||
}
|
||||
|
||||
/// Creates a new `DiagnosticBuilder` with an already constructed
|
||||
/// diagnostic.
|
||||
#[inline(always)] // box
|
||||
pub fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> DiagnosticBuilder<'a> {
|
||||
DiagnosticBuilder {
|
||||
handler,
|
||||
diagnostic: Box::new(diagnostic),
|
||||
allow_suggestions: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Debug for DiagnosticBuilder<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.diagnostic.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Destructor bomb - a `DiagnosticBuilder` must be either emitted or canceled
|
||||
/// or we emit a bug.
|
||||
impl<'a> Drop for DiagnosticBuilder<'a> {
|
||||
fn drop(&mut self) {
|
||||
if !panicking() && !self.cancelled() {
|
||||
let mut db = DiagnosticBuilder::new(
|
||||
self.handler,
|
||||
Level::Bug,
|
||||
"Error constructed but not emitted",
|
||||
);
|
||||
db.emit();
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
}
|
||||
1647
third-party/vendor/swc_common/src/errors/emitter.rs
vendored
Normal file
1647
third-party/vendor/swc_common/src/errors/emitter.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
122
third-party/vendor/swc_common/src/errors/lock.rs
vendored
Normal file
122
third-party/vendor/swc_common/src/errors/lock.rs
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Bindings to acquire a global named lock.
|
||||
//!
|
||||
//! This is intended to be used to synchronize multiple compiler processes to
|
||||
//! ensure that we can output complete errors without interleaving on Windows.
|
||||
//! Note that this is currently only needed for allowing only one 32-bit MSVC
|
||||
//! linker to execute at once on MSVC hosts, so this is only implemented for
|
||||
//! `cfg(windows)`. Also note that this may not always be used on Windows,
|
||||
//! only when targeting 32-bit MSVC.
|
||||
//!
|
||||
//! For more information about why this is necessary, see where this is called.
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
#[cfg(windows)]
|
||||
#[allow(nonstandard_style)]
|
||||
pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
|
||||
use std::{ffi::CString, io};
|
||||
|
||||
type LPSECURITY_ATTRIBUTES = *mut u8;
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
type BOOL = i32;
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
type LPCSTR = *const u8;
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
type HANDLE = *mut u8;
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
type DWORD = u32;
|
||||
|
||||
const INFINITE: DWORD = !0;
|
||||
const WAIT_OBJECT_0: DWORD = 0;
|
||||
const WAIT_ABANDONED: DWORD = 0x00000080;
|
||||
|
||||
extern "system" {
|
||||
fn CreateMutexA(
|
||||
lpMutexAttributes: LPSECURITY_ATTRIBUTES,
|
||||
bInitialOwner: BOOL,
|
||||
lpName: LPCSTR,
|
||||
) -> HANDLE;
|
||||
fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
|
||||
fn ReleaseMutex(hMutex: HANDLE) -> BOOL;
|
||||
fn CloseHandle(hObject: HANDLE) -> BOOL;
|
||||
}
|
||||
|
||||
struct Handle(HANDLE);
|
||||
|
||||
impl Drop for Handle {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
CloseHandle(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Guard(Handle);
|
||||
|
||||
impl Drop for Guard {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ReleaseMutex((self.0).0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let cname = CString::new(name).unwrap();
|
||||
unsafe {
|
||||
// Create a named mutex, with no security attributes and also not
|
||||
// acquired when we create it.
|
||||
//
|
||||
// This will silently create one if it doesn't already exist, or it'll
|
||||
// open up a handle to one if it already exists.
|
||||
let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr() as *const u8);
|
||||
if mutex.is_null() {
|
||||
panic!(
|
||||
"failed to create global mutex named `{}`: {}",
|
||||
name,
|
||||
io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
let mutex = Handle(mutex);
|
||||
|
||||
// Acquire the lock through `WaitForSingleObject`.
|
||||
//
|
||||
// A return value of `WAIT_OBJECT_0` means we successfully acquired it.
|
||||
//
|
||||
// A return value of `WAIT_ABANDONED` means that the previous holder of
|
||||
// the thread exited without calling `ReleaseMutex`. This can happen,
|
||||
// for example, when the compiler crashes or is interrupted via ctrl-c
|
||||
// or the like. In this case, however, we are still transferred
|
||||
// ownership of the lock so we continue.
|
||||
//
|
||||
// If an error happens.. well... that's surprising!
|
||||
match WaitForSingleObject(mutex.0, INFINITE) {
|
||||
WAIT_OBJECT_0 | WAIT_ABANDONED => {}
|
||||
code => {
|
||||
panic!(
|
||||
"WaitForSingleObject failed on global mutex named `{}`: {} (ret={:x})",
|
||||
name,
|
||||
io::Error::last_os_error(),
|
||||
code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Return a guard which will call `ReleaseMutex` when dropped.
|
||||
Box::new(Guard(mutex))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
pub fn acquire_global_lock(_name: &str) -> Box<dyn Any> {
|
||||
Box::new(())
|
||||
}
|
||||
961
third-party/vendor/swc_common/src/errors/mod.rs
vendored
Normal file
961
third-party/vendor/swc_common/src/errors/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,961 @@
|
|||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cell::RefCell,
|
||||
error, fmt,
|
||||
io::Write,
|
||||
panic,
|
||||
sync::atomic::{AtomicUsize, Ordering::SeqCst},
|
||||
};
|
||||
|
||||
#[cfg(feature = "tty-emitter")]
|
||||
use termcolor::{Color, ColorSpec};
|
||||
|
||||
use self::Level::*;
|
||||
pub use self::{
|
||||
diagnostic::{Diagnostic, DiagnosticId, DiagnosticStyledString, SubDiagnostic},
|
||||
diagnostic_builder::DiagnosticBuilder,
|
||||
emitter::{ColorConfig, Emitter, EmitterWriter},
|
||||
};
|
||||
use crate::{
|
||||
collections::AHashSet,
|
||||
rustc_data_structures::stable_hasher::StableHasher,
|
||||
sync::{Lock, LockCell, Lrc},
|
||||
syntax_pos::{BytePos, FileLinesResult, FileName, Loc, MultiSpan, Span, NO_EXPANSION},
|
||||
SpanSnippetError,
|
||||
};
|
||||
|
||||
mod diagnostic;
|
||||
mod diagnostic_builder;
|
||||
pub mod emitter;
|
||||
mod lock;
|
||||
mod snippet;
|
||||
mod styled_buffer;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(u32)))]
|
||||
pub enum Applicability {
|
||||
MachineApplicable,
|
||||
HasPlaceholders,
|
||||
MaybeIncorrect,
|
||||
Unspecified,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct CodeSuggestion {
|
||||
/// Each substitute can have multiple variants due to multiple
|
||||
/// applicable suggestions
|
||||
///
|
||||
/// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
|
||||
/// `foo` and `bar` on their own:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// vec![
|
||||
/// Substitution {
|
||||
/// parts: vec![(0..3, "a"), (4..7, "b")],
|
||||
/// },
|
||||
/// Substitution {
|
||||
/// parts: vec![(0..3, "x"), (4..7, "y")],
|
||||
/// },
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// or by replacing the entire span:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// vec![
|
||||
/// Substitution {
|
||||
/// parts: vec![(0..7, "a.b")],
|
||||
/// },
|
||||
/// Substitution {
|
||||
/// parts: vec![(0..7, "x.y")],
|
||||
/// },
|
||||
/// ]
|
||||
/// ```
|
||||
pub substitutions: Vec<Substitution>,
|
||||
pub msg: String,
|
||||
pub show_code_when_inline: bool,
|
||||
/// Whether or not the suggestion is approximate
|
||||
///
|
||||
/// Sometimes we may show suggestions with placeholders,
|
||||
/// which are useful for users but not useful for
|
||||
/// tools like rustfix
|
||||
pub applicability: Applicability,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
/// See the docs on `CodeSuggestion::substitutions`
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct Substitution {
|
||||
pub parts: Vec<SubstitutionPart>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct SubstitutionPart {
|
||||
pub span: Span,
|
||||
pub snippet: String,
|
||||
}
|
||||
|
||||
pub type SourceMapperDyn = dyn SourceMapper;
|
||||
|
||||
pub trait SourceMapper: crate::sync::Send + crate::sync::Sync {
|
||||
fn lookup_char_pos(&self, pos: BytePos) -> Loc;
|
||||
fn span_to_lines(&self, sp: Span) -> FileLinesResult;
|
||||
fn span_to_string(&self, sp: Span) -> String;
|
||||
fn span_to_filename(&self, sp: Span) -> FileName;
|
||||
fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option<Span>;
|
||||
fn call_span_if_macro(&self, sp: Span) -> Span;
|
||||
fn doctest_offset_line(&self, line: usize) -> usize;
|
||||
fn span_to_snippet(&self, sp: Span) -> Result<String, Box<SpanSnippetError>>;
|
||||
}
|
||||
|
||||
impl CodeSuggestion {
|
||||
/// Returns the assembled code suggestions and whether they should be shown
|
||||
/// with an underline.
|
||||
pub fn splice_lines(&self, cm: &SourceMapperDyn) -> Vec<(String, Vec<SubstitutionPart>)> {
|
||||
use crate::syntax_pos::{CharPos, Pos};
|
||||
|
||||
fn push_trailing(
|
||||
buf: &mut String,
|
||||
line_opt: Option<&Cow<'_, str>>,
|
||||
lo: &Loc,
|
||||
hi_opt: Option<&Loc>,
|
||||
) {
|
||||
let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
|
||||
if let Some(line) = line_opt {
|
||||
if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
|
||||
let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
|
||||
buf.push_str(match hi_opt {
|
||||
Some(hi) => &line[lo..hi],
|
||||
None => &line[lo..],
|
||||
});
|
||||
}
|
||||
if hi_opt.is_none() {
|
||||
buf.push('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert!(!self.substitutions.is_empty());
|
||||
|
||||
self.substitutions
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|mut substitution| {
|
||||
// Assumption: all spans are in the same file, and all spans
|
||||
// are disjoint. Sort in ascending order.
|
||||
substitution.parts.sort_by_key(|part| part.span.lo());
|
||||
|
||||
// Find the bounding span.
|
||||
let lo = substitution
|
||||
.parts
|
||||
.iter()
|
||||
.map(|part| part.span.lo())
|
||||
.min()
|
||||
.unwrap();
|
||||
let hi = substitution
|
||||
.parts
|
||||
.iter()
|
||||
.map(|part| part.span.hi())
|
||||
.min()
|
||||
.unwrap();
|
||||
let bounding_span = Span::new(lo, hi, NO_EXPANSION);
|
||||
let lines = cm.span_to_lines(bounding_span).unwrap();
|
||||
assert!(!lines.lines.is_empty());
|
||||
|
||||
// To build up the result, we do this for each span:
|
||||
// - push the line segment trailing the previous span (at the beginning a
|
||||
// "phantom" span pointing at the start of the line)
|
||||
// - push lines between the previous and current span (if any)
|
||||
// - if the previous and current span are not on the same line push the line
|
||||
// segment leading up to the current span
|
||||
// - splice in the span substitution
|
||||
//
|
||||
// Finally push the trailing line segment of the last span
|
||||
let fm = &lines.file;
|
||||
let mut prev_hi = cm.lookup_char_pos(bounding_span.lo());
|
||||
prev_hi.col = CharPos::from_usize(0);
|
||||
|
||||
let mut prev_line = fm.get_line(lines.lines[0].line_index);
|
||||
let mut buf = String::new();
|
||||
|
||||
for part in &substitution.parts {
|
||||
let cur_lo = cm.lookup_char_pos(part.span.lo());
|
||||
if prev_hi.line == cur_lo.line {
|
||||
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
|
||||
} else {
|
||||
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
|
||||
// push lines between the previous and current span (if any)
|
||||
for idx in prev_hi.line..(cur_lo.line - 1) {
|
||||
if let Some(line) = fm.get_line(idx) {
|
||||
buf.push_str(line.as_ref());
|
||||
buf.push('\n');
|
||||
}
|
||||
}
|
||||
if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
|
||||
buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
|
||||
}
|
||||
}
|
||||
buf.push_str(&part.snippet);
|
||||
prev_hi = cm.lookup_char_pos(part.span.hi());
|
||||
prev_line = fm.get_line(prev_hi.line - 1);
|
||||
}
|
||||
// if the replacement already ends with a newline, don't print the next line
|
||||
if !buf.ends_with('\n') {
|
||||
push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
|
||||
}
|
||||
// remove trailing newlines
|
||||
while buf.ends_with('\n') {
|
||||
buf.pop();
|
||||
}
|
||||
(buf, substitution.parts)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Used as a return value to signify a fatal error occurred. (It is also
|
||||
/// used as the argument to panic at the moment, but that will eventually
|
||||
/// not be true.)
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[must_use]
|
||||
pub struct FatalError;
|
||||
|
||||
pub struct FatalErrorMarker;
|
||||
|
||||
// // Don't implement Send on FatalError. This makes it impossible to
|
||||
// // panic!(FatalError). We don't want to invoke the panic handler and print a
|
||||
// // backtrace for fatal errors.
|
||||
// impl !Send for FatalError {}
|
||||
|
||||
impl FatalError {
|
||||
pub fn raise(self) -> ! {
|
||||
panic::resume_unwind(Box::new(FatalErrorMarker))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FatalError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "parser fatal error")
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for FatalError {
|
||||
fn description(&self) -> &str {
|
||||
"The parser has encountered a fatal error"
|
||||
}
|
||||
}
|
||||
|
||||
/// Signifies that the compiler died with an explicit call to `.bug`
|
||||
/// or `.span_bug` rather than a failed assertion, etc.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ExplicitBug;
|
||||
|
||||
impl fmt::Display for ExplicitBug {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "parser internal bug")
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for ExplicitBug {
|
||||
fn description(&self) -> &str {
|
||||
"The parser has encountered an internal bug"
|
||||
}
|
||||
}
|
||||
|
||||
/// A handler deals with errors; certain errors
|
||||
/// (fatal, bug, unimpl) may cause immediate exit,
|
||||
/// others log errors for later reporting.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// `swc` provides a global-like variable ([HANDLER]) of type `Handler` that can
|
||||
/// be used to report errors.
|
||||
///
|
||||
/// You can refer to [the lint rules](https://github.com/swc-project/swc/tree/main/crates/swc_ecma_lints/src/rules) for other example usages.
|
||||
/// All lint rules have code for error reporting.
|
||||
///
|
||||
/// ## Error reporting in swc
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use swc_common::errors::HANDLER;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// HANDLER.with(|handler| {
|
||||
/// // You can access the handler for the current file using HANDLER.with.
|
||||
///
|
||||
/// // We now report an error
|
||||
///
|
||||
/// // `struct_span_err` creates a builder for a diagnostic.
|
||||
/// // The span passed to `struct_span_err` will used to point the problematic code.
|
||||
/// //
|
||||
/// // You may provide additional information, like a previous declaration of parameter.
|
||||
/// handler
|
||||
/// .struct_span_err(
|
||||
/// span,
|
||||
/// &format!("`{}` used as parameter more than once", js_word),
|
||||
/// )
|
||||
/// .span_note(
|
||||
/// old_span,
|
||||
/// &format!("previous definition of `{}` here", js_word),
|
||||
/// )
|
||||
/// .emit();
|
||||
/// });
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct Handler {
|
||||
pub flags: HandlerFlags,
|
||||
|
||||
err_count: AtomicUsize,
|
||||
emitter: Lock<Box<dyn Emitter>>,
|
||||
continue_after_error: LockCell<bool>,
|
||||
delayed_span_bugs: Lock<Vec<Diagnostic>>,
|
||||
|
||||
// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
|
||||
// emitting the same diagnostic with extended help (`--teach`) twice, which
|
||||
// would be unnecessary repetition.
|
||||
taught_diagnostics: Lock<AHashSet<DiagnosticId>>,
|
||||
|
||||
/// Used to suggest rustc --explain <error code>
|
||||
emitted_diagnostic_codes: Lock<AHashSet<DiagnosticId>>,
|
||||
|
||||
// This set contains a hash of every diagnostic that has been emitted by
|
||||
// this handler. These hashes is used to avoid emitting the same error
|
||||
// twice.
|
||||
emitted_diagnostics: Lock<AHashSet<u128>>,
|
||||
}
|
||||
|
||||
fn default_track_diagnostic(_: &Diagnostic) {}
|
||||
|
||||
thread_local!(pub static TRACK_DIAGNOSTICS: RefCell<Box<dyn Fn(&Diagnostic)>> =
|
||||
RefCell::new(Box::new(default_track_diagnostic)));
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct HandlerFlags {
|
||||
/// If false, warning-level lints are suppressed.
|
||||
/// (rustc: see `--allow warnings` and `--cap-lints`)
|
||||
pub can_emit_warnings: bool,
|
||||
/// If true, error-level diagnostics are upgraded to bug-level.
|
||||
/// (rustc: see `-Z treat-err-as-bug`)
|
||||
pub treat_err_as_bug: bool,
|
||||
/// If true, immediately emit diagnostics that would otherwise be buffered.
|
||||
/// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
|
||||
pub dont_buffer_diagnostics: bool,
|
||||
/// If true, immediately print bugs registered with `delay_span_bug`.
|
||||
/// (rustc: see `-Z report-delayed-bugs`)
|
||||
pub report_delayed_bugs: bool,
|
||||
/// show macro backtraces even for non-local macros.
|
||||
/// (rustc: see `-Z external-macro-backtrace`)
|
||||
pub external_macro_backtrace: bool,
|
||||
}
|
||||
|
||||
impl Drop for Handler {
|
||||
fn drop(&mut self) {
|
||||
if self.err_count() == 0 {
|
||||
let mut bugs = self.delayed_span_bugs.borrow_mut();
|
||||
let has_bugs = !bugs.is_empty();
|
||||
for bug in bugs.drain(..) {
|
||||
DiagnosticBuilder::new_diagnostic(self, bug).emit();
|
||||
}
|
||||
if has_bugs {
|
||||
panic!("no errors encountered even though `delay_span_bug` issued");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Handler {
|
||||
#[cfg(feature = "tty-emitter")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "tty-emitter")))]
|
||||
pub fn with_tty_emitter(
|
||||
color_config: ColorConfig,
|
||||
can_emit_warnings: bool,
|
||||
treat_err_as_bug: bool,
|
||||
cm: Option<Lrc<SourceMapperDyn>>,
|
||||
) -> Handler {
|
||||
Handler::with_tty_emitter_and_flags(
|
||||
color_config,
|
||||
cm,
|
||||
HandlerFlags {
|
||||
can_emit_warnings,
|
||||
treat_err_as_bug,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "tty-emitter")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "tty-emitter")))]
|
||||
pub fn with_tty_emitter_and_flags(
|
||||
color_config: ColorConfig,
|
||||
cm: Option<Lrc<SourceMapperDyn>>,
|
||||
flags: HandlerFlags,
|
||||
) -> Handler {
|
||||
let emitter = Box::new(EmitterWriter::stderr(color_config, cm, false, false));
|
||||
Handler::with_emitter_and_flags(emitter, flags)
|
||||
}
|
||||
|
||||
/// Example implementation of [Emitter] is [EmitterWriter]
|
||||
pub fn with_emitter(
|
||||
can_emit_warnings: bool,
|
||||
treat_err_as_bug: bool,
|
||||
emitter: Box<dyn Emitter>,
|
||||
) -> Handler {
|
||||
Handler::with_emitter_and_flags(
|
||||
emitter,
|
||||
HandlerFlags {
|
||||
can_emit_warnings,
|
||||
treat_err_as_bug,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Calls [Self::with_emitter] with [EmitterWriter].
|
||||
pub fn with_emitter_writer(
|
||||
dst: Box<dyn Write + Send>,
|
||||
cm: Option<Lrc<SourceMapperDyn>>,
|
||||
) -> Handler {
|
||||
Handler::with_emitter(
|
||||
true,
|
||||
false,
|
||||
Box::new(EmitterWriter::new(dst, cm, false, true)),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn with_emitter_and_flags(e: Box<dyn Emitter>, flags: HandlerFlags) -> Handler {
|
||||
Handler {
|
||||
flags,
|
||||
err_count: AtomicUsize::new(0),
|
||||
emitter: Lock::new(e),
|
||||
continue_after_error: LockCell::new(true),
|
||||
delayed_span_bugs: Lock::new(Vec::new()),
|
||||
taught_diagnostics: Default::default(),
|
||||
emitted_diagnostic_codes: Default::default(),
|
||||
emitted_diagnostics: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_continue_after_error(&self, continue_after_error: bool) {
|
||||
self.continue_after_error.set(continue_after_error);
|
||||
}
|
||||
|
||||
/// Resets the diagnostic error count as well as the cached emitted
|
||||
/// diagnostics.
|
||||
///
|
||||
/// NOTE: DO NOT call this function from rustc. It is only meant to be
|
||||
/// called from external tools that want to reuse a `Parser` cleaning
|
||||
/// the previously emitted diagnostics as well as the overall count of
|
||||
/// emitted error diagnostics.
|
||||
pub fn reset_err_count(&self) {
|
||||
// actually frees the underlying memory (which `clear` would not do)
|
||||
*self.emitted_diagnostics.borrow_mut() = Default::default();
|
||||
self.err_count.store(0, SeqCst);
|
||||
}
|
||||
|
||||
pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> {
|
||||
DiagnosticBuilder::new(self, Level::Cancelled, "")
|
||||
}
|
||||
|
||||
pub fn struct_span_warn<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
|
||||
result.set_span(sp);
|
||||
if !self.flags.can_emit_warnings {
|
||||
result.cancel();
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
|
||||
result.set_span(sp);
|
||||
result.code(code);
|
||||
if !self.flags.can_emit_warnings {
|
||||
result.cancel();
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
|
||||
if !self.flags.can_emit_warnings {
|
||||
result.cancel();
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn struct_span_err<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
|
||||
result.set_span(sp);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
|
||||
result.set_span(sp);
|
||||
result.code(code);
|
||||
result
|
||||
}
|
||||
|
||||
// FIXME: This method should be removed (every error should have an associated
|
||||
// error code).
|
||||
pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
DiagnosticBuilder::new(self, Level::Error, msg)
|
||||
}
|
||||
|
||||
pub fn struct_err_with_code<'a>(
|
||||
&'a self,
|
||||
msg: &str,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
|
||||
result.code(code);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
|
||||
result.set_span(sp);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
code: DiagnosticId,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
|
||||
result.set_span(sp);
|
||||
result.code(code);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
DiagnosticBuilder::new(self, Level::Fatal, msg)
|
||||
}
|
||||
|
||||
pub fn cancel(&self, err: &mut DiagnosticBuilder<'_>) {
|
||||
err.cancel();
|
||||
}
|
||||
|
||||
fn panic_if_treat_err_as_bug(&self) {
|
||||
if self.flags.treat_err_as_bug {
|
||||
panic!("encountered error with `-Z treat_err_as_bug");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
|
||||
self.emit(&sp.into(), msg, Fatal);
|
||||
FatalError
|
||||
}
|
||||
|
||||
pub fn span_fatal_with_code<S: Into<MultiSpan>>(
|
||||
&self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
code: DiagnosticId,
|
||||
) -> FatalError {
|
||||
self.emit_with_code(&sp.into(), msg, code, Fatal);
|
||||
FatalError
|
||||
}
|
||||
|
||||
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
self.emit(&sp.into(), msg, Error);
|
||||
}
|
||||
|
||||
pub fn mut_span_err<'a, S: Into<MultiSpan>>(
|
||||
&'a self,
|
||||
sp: S,
|
||||
msg: &str,
|
||||
) -> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
|
||||
result.set_span(sp);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
|
||||
self.emit_with_code(&sp.into(), msg, code, Error);
|
||||
}
|
||||
|
||||
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
self.emit(&sp.into(), msg, Warning);
|
||||
}
|
||||
|
||||
pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) {
|
||||
self.emit_with_code(&sp.into(), msg, code, Warning);
|
||||
}
|
||||
|
||||
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
|
||||
self.emit(&sp.into(), msg, Bug);
|
||||
panic!("{}", ExplicitBug);
|
||||
}
|
||||
|
||||
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
if self.flags.treat_err_as_bug {
|
||||
// FIXME: don't abort here if report_delayed_bugs is off
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
let mut diagnostic = Diagnostic::new(Level::Bug, msg);
|
||||
diagnostic.set_span(sp.into());
|
||||
self.delay_as_bug(diagnostic);
|
||||
}
|
||||
|
||||
fn delay_as_bug(&self, diagnostic: Diagnostic) {
|
||||
if self.flags.report_delayed_bugs {
|
||||
DiagnosticBuilder::new_diagnostic(self, diagnostic.clone()).emit();
|
||||
}
|
||||
self.delayed_span_bugs.borrow_mut().push(diagnostic);
|
||||
}
|
||||
|
||||
pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
self.emit(&sp.into(), msg, Bug);
|
||||
}
|
||||
|
||||
pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
self.emit(&sp.into(), msg, Note);
|
||||
}
|
||||
|
||||
pub fn span_note_diag<'a>(&'a self, sp: Span, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
let mut db = DiagnosticBuilder::new(self, Note, msg);
|
||||
db.set_span(sp);
|
||||
db
|
||||
}
|
||||
|
||||
pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
|
||||
self.span_bug(sp, &format!("unimplemented {}", msg));
|
||||
}
|
||||
|
||||
pub fn failure(&self, msg: &str) {
|
||||
DiagnosticBuilder::new(self, FailureNote, msg).emit()
|
||||
}
|
||||
|
||||
pub fn fatal(&self, msg: &str) -> FatalError {
|
||||
if self.flags.treat_err_as_bug {
|
||||
self.bug(msg);
|
||||
}
|
||||
DiagnosticBuilder::new(self, Fatal, msg).emit();
|
||||
FatalError
|
||||
}
|
||||
|
||||
pub fn err(&self, msg: &str) {
|
||||
if self.flags.treat_err_as_bug {
|
||||
self.bug(msg);
|
||||
}
|
||||
let mut db = DiagnosticBuilder::new(self, Error, msg);
|
||||
db.emit();
|
||||
}
|
||||
|
||||
pub fn warn(&self, msg: &str) {
|
||||
let mut db = DiagnosticBuilder::new(self, Warning, msg);
|
||||
db.emit();
|
||||
}
|
||||
|
||||
pub fn note_without_error(&self, msg: &str) {
|
||||
let mut db = DiagnosticBuilder::new(self, Note, msg);
|
||||
db.emit();
|
||||
}
|
||||
|
||||
pub fn bug(&self, msg: &str) -> ! {
|
||||
let mut db = DiagnosticBuilder::new(self, Bug, msg);
|
||||
db.emit();
|
||||
panic!("{}", ExplicitBug);
|
||||
}
|
||||
|
||||
pub fn unimpl(&self, msg: &str) -> ! {
|
||||
self.bug(&format!("unimplemented {}", msg));
|
||||
}
|
||||
|
||||
fn bump_err_count(&self) {
|
||||
self.panic_if_treat_err_as_bug();
|
||||
self.err_count.fetch_add(1, SeqCst);
|
||||
}
|
||||
|
||||
pub fn err_count(&self) -> usize {
|
||||
self.err_count.load(SeqCst)
|
||||
}
|
||||
|
||||
pub fn has_errors(&self) -> bool {
|
||||
self.err_count() > 0
|
||||
}
|
||||
|
||||
pub fn print_error_count(&self) {
|
||||
let s = match self.err_count() {
|
||||
0 => return,
|
||||
1 => "aborting due to previous error".to_string(),
|
||||
_ => format!("aborting due to {} previous errors", self.err_count()),
|
||||
};
|
||||
|
||||
let _ = self.fatal(&s);
|
||||
|
||||
let can_show_explain = self.emitter.borrow().should_show_explain();
|
||||
let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty();
|
||||
if can_show_explain && are_there_diagnostics {
|
||||
let mut error_codes = self
|
||||
.emitted_diagnostic_codes
|
||||
.borrow()
|
||||
.iter()
|
||||
.filter_map(|x| match *x {
|
||||
DiagnosticId::Error(ref s) => Some(s.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if !error_codes.is_empty() {
|
||||
error_codes.sort();
|
||||
if error_codes.len() > 1 {
|
||||
let limit = if error_codes.len() > 9 {
|
||||
9
|
||||
} else {
|
||||
error_codes.len()
|
||||
};
|
||||
self.failure(&format!(
|
||||
"Some errors occurred: {}{}",
|
||||
error_codes[..limit].join(", "),
|
||||
if error_codes.len() > 9 { "..." } else { "." }
|
||||
));
|
||||
self.failure(&format!(
|
||||
"For more information about an error, try `rustc --explain {}`.",
|
||||
&error_codes[0]
|
||||
));
|
||||
} else {
|
||||
self.failure(&format!(
|
||||
"For more information about this error, try `rustc --explain {}`.",
|
||||
&error_codes[0]
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn abort_if_errors(&self) {
|
||||
if self.err_count() == 0 {
|
||||
return;
|
||||
}
|
||||
FatalError.raise();
|
||||
}
|
||||
|
||||
pub fn emit(&self, msp: &MultiSpan, msg: &str, lvl: Level) {
|
||||
if lvl == Warning && !self.flags.can_emit_warnings {
|
||||
return;
|
||||
}
|
||||
let mut db = DiagnosticBuilder::new(self, lvl, msg);
|
||||
db.set_span(msp.clone());
|
||||
db.emit();
|
||||
if !self.continue_after_error.get() {
|
||||
self.abort_if_errors();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn emit_with_code(&self, msp: &MultiSpan, msg: &str, code: DiagnosticId, lvl: Level) {
|
||||
if lvl == Warning && !self.flags.can_emit_warnings {
|
||||
return;
|
||||
}
|
||||
let mut db = DiagnosticBuilder::new_with_code(self, lvl, Some(code), msg);
|
||||
db.set_span(msp.clone());
|
||||
db.emit();
|
||||
if !self.continue_after_error.get() {
|
||||
self.abort_if_errors();
|
||||
}
|
||||
}
|
||||
|
||||
/// `true` if we haven't taught a diagnostic with this code already.
|
||||
/// The caller must then teach the user about such a diagnostic.
|
||||
///
|
||||
/// Used to suppress emitting the same error multiple times with extended
|
||||
/// explanation when calling `-Z teach`.
|
||||
pub fn must_teach(&self, code: &DiagnosticId) -> bool {
|
||||
self.taught_diagnostics.borrow_mut().insert(code.clone())
|
||||
}
|
||||
|
||||
pub fn force_print_db(&self, mut db: DiagnosticBuilder<'_>) {
|
||||
self.emitter.borrow_mut().emit(&db);
|
||||
db.cancel();
|
||||
}
|
||||
|
||||
fn emit_db(&self, db: &DiagnosticBuilder<'_>) {
|
||||
let diagnostic = &**db;
|
||||
|
||||
TRACK_DIAGNOSTICS.with(|track_diagnostics| {
|
||||
track_diagnostics.borrow()(diagnostic);
|
||||
});
|
||||
|
||||
if let Some(ref code) = diagnostic.code {
|
||||
self.emitted_diagnostic_codes
|
||||
.borrow_mut()
|
||||
.insert(code.clone());
|
||||
}
|
||||
|
||||
let diagnostic_hash = {
|
||||
use std::hash::Hash;
|
||||
let mut hasher = StableHasher::new();
|
||||
diagnostic.hash(&mut hasher);
|
||||
hasher.finish()
|
||||
};
|
||||
|
||||
// Only emit the diagnostic if we haven't already emitted an equivalent
|
||||
// one:
|
||||
if self
|
||||
.emitted_diagnostics
|
||||
.borrow_mut()
|
||||
.insert(diagnostic_hash)
|
||||
{
|
||||
self.emitter.borrow_mut().emit(db);
|
||||
if db.is_error() {
|
||||
self.bump_err_count();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(u32)))]
|
||||
pub enum Level {
|
||||
Bug,
|
||||
Fatal,
|
||||
// An error which while not immediately fatal, should stop the compiler
|
||||
// progressing beyond the current phase.
|
||||
PhaseFatal,
|
||||
Error,
|
||||
Warning,
|
||||
Note,
|
||||
Help,
|
||||
Cancelled,
|
||||
FailureNote,
|
||||
}
|
||||
|
||||
impl fmt::Display for Level {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.to_str().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Level {
|
||||
#[cfg(feature = "tty-emitter")]
|
||||
fn color(self) -> ColorSpec {
|
||||
let mut spec = ColorSpec::new();
|
||||
match self {
|
||||
Bug | Fatal | PhaseFatal | Error => {
|
||||
spec.set_fg(Some(Color::Red)).set_intense(true);
|
||||
}
|
||||
Warning => {
|
||||
spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
|
||||
}
|
||||
Note => {
|
||||
spec.set_fg(Some(Color::Green)).set_intense(true);
|
||||
}
|
||||
Help => {
|
||||
spec.set_fg(Some(Color::Cyan)).set_intense(true);
|
||||
}
|
||||
FailureNote => {}
|
||||
Cancelled => unreachable!(),
|
||||
}
|
||||
spec
|
||||
}
|
||||
|
||||
pub fn to_str(self) -> &'static str {
|
||||
match self {
|
||||
Bug => "error: internal compiler error",
|
||||
Fatal | PhaseFatal | Error => "error",
|
||||
Warning => "warning",
|
||||
Note => "note",
|
||||
Help => "help",
|
||||
FailureNote => "",
|
||||
Cancelled => panic!("Shouldn't call on cancelled error"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_failure_note(self) -> bool {
|
||||
matches!(self, FailureNote)
|
||||
}
|
||||
}
|
||||
|
||||
better_scoped_tls::scoped_tls!(
|
||||
/// Used for error reporting in transform.
|
||||
///
|
||||
/// This should be only used for errors from the api which does not returning errors.
|
||||
///
|
||||
/// e.g.
|
||||
/// - `parser` should not use this.
|
||||
/// - `transforms` should use this to report error, as it does not return [Result].
|
||||
///
|
||||
/// See [Handler] for actual usage examples.
|
||||
pub static HANDLER: Handler
|
||||
);
|
||||
203
third-party/vendor/swc_common/src/errors/snippet.rs
vendored
Normal file
203
third-party/vendor/swc_common/src/errors/snippet.rs
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Code for annotating snippets.
|
||||
|
||||
use super::Level;
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub struct Line {
|
||||
pub line_index: usize,
|
||||
pub annotations: Vec<Annotation>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub struct MultilineAnnotation {
|
||||
pub depth: usize,
|
||||
pub line_start: usize,
|
||||
pub line_end: usize,
|
||||
pub start_col: usize,
|
||||
pub end_col: usize,
|
||||
pub is_primary: bool,
|
||||
pub label: Option<String>,
|
||||
}
|
||||
|
||||
impl MultilineAnnotation {
|
||||
pub fn increase_depth(&mut self) {
|
||||
self.depth += 1;
|
||||
}
|
||||
|
||||
pub fn as_start(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: self.start_col,
|
||||
end_col: self.start_col + 1,
|
||||
is_primary: self.is_primary,
|
||||
label: None,
|
||||
annotation_type: AnnotationType::MultilineStart(self.depth),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_end(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: self.end_col.saturating_sub(1),
|
||||
end_col: self.end_col,
|
||||
is_primary: self.is_primary,
|
||||
label: self.label.clone(),
|
||||
annotation_type: AnnotationType::MultilineEnd(self.depth),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_line(&self) -> Annotation {
|
||||
Annotation {
|
||||
start_col: 0,
|
||||
end_col: 0,
|
||||
is_primary: self.is_primary,
|
||||
label: None,
|
||||
annotation_type: AnnotationType::MultilineLine(self.depth),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub enum AnnotationType {
|
||||
/// Annotation under a single line of code
|
||||
Singleline,
|
||||
|
||||
/// Annotation enclosing the first and last character of a multiline span
|
||||
Multiline(MultilineAnnotation),
|
||||
|
||||
// The Multiline type above is replaced with the following three in order
|
||||
// to reuse the current label drawing code.
|
||||
//
|
||||
// Each of these corresponds to one part of the following diagram:
|
||||
//
|
||||
// x | foo(1 + bar(x,
|
||||
// | _________^ < MultilineStart
|
||||
// x | | y), < MultilineLine
|
||||
// | |______________^ label < MultilineEnd
|
||||
// x | z);
|
||||
/// Annotation marking the first character of a fully shown multiline span
|
||||
MultilineStart(usize),
|
||||
/// Annotation marking the last character of a fully shown multiline span
|
||||
MultilineEnd(usize),
|
||||
/// Line at the left enclosing the lines of a fully shown multiline span
|
||||
// Just a placeholder for the drawing algorithm, to know that it shouldn't skip the first 4
|
||||
// and last 2 lines of code. The actual line is drawn in `emit_message_default` and not in
|
||||
// `draw_multiline_line`.
|
||||
MultilineLine(usize),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub struct Annotation {
|
||||
/// Start column, 0-based indexing -- counting *characters*, not
|
||||
/// utf-8 bytes. Note that it is important that this field goes
|
||||
/// first, so that when we sort, we sort orderings by start
|
||||
/// column.
|
||||
pub start_col: usize,
|
||||
|
||||
/// End column within the line (exclusive)
|
||||
pub end_col: usize,
|
||||
|
||||
/// Is this annotation derived from primary span
|
||||
pub is_primary: bool,
|
||||
|
||||
/// Optional label to display adjacent to the annotation.
|
||||
pub label: Option<String>,
|
||||
|
||||
/// Is this a single line, multiline or multiline span minimized down to a
|
||||
/// smaller span.
|
||||
pub annotation_type: AnnotationType,
|
||||
}
|
||||
|
||||
impl Annotation {
|
||||
/// Whether this annotation is a vertical line placeholder.
|
||||
pub fn is_line(&self) -> bool {
|
||||
matches!(self.annotation_type, AnnotationType::MultilineLine(_))
|
||||
}
|
||||
|
||||
pub fn is_multiline(&self) -> bool {
|
||||
matches!(
|
||||
self.annotation_type,
|
||||
AnnotationType::Multiline(_)
|
||||
| AnnotationType::MultilineStart(_)
|
||||
| AnnotationType::MultilineLine(_)
|
||||
| AnnotationType::MultilineEnd(_)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
// Account for usize underflows
|
||||
if self.end_col > self.start_col {
|
||||
self.end_col - self.start_col
|
||||
} else {
|
||||
self.start_col - self.end_col
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_label(&self) -> bool {
|
||||
if let Some(ref label) = self.label {
|
||||
// Consider labels with no text as effectively not being there
|
||||
// to avoid weird output with unnecessary vertical lines, like:
|
||||
//
|
||||
// X | fn foo(x: u32) {
|
||||
// | -------^------
|
||||
// | | |
|
||||
// | |
|
||||
// |
|
||||
//
|
||||
// Note that this would be the complete output users would see.
|
||||
!label.is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn takes_space(&self) -> bool {
|
||||
// Multiline annotations always have to keep vertical space.
|
||||
matches!(
|
||||
self.annotation_type,
|
||||
AnnotationType::MultilineStart(_) | AnnotationType::MultilineEnd(_)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StyledString {
|
||||
pub text: String,
|
||||
pub style: Style,
|
||||
}
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "diagnostic-serde",
|
||||
derive(serde::Serialize, serde::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(u32)))]
|
||||
pub enum Style {
|
||||
MainHeaderMsg,
|
||||
HeaderMsg,
|
||||
LineAndColumn,
|
||||
LineNumber,
|
||||
Quotation,
|
||||
UnderlinePrimary,
|
||||
UnderlineSecondary,
|
||||
LabelPrimary,
|
||||
LabelSecondary,
|
||||
OldSchoolNoteText,
|
||||
NoStyle,
|
||||
Level(Level),
|
||||
Highlight,
|
||||
}
|
||||
170
third-party/vendor/swc_common/src/errors/styled_buffer.rs
vendored
Normal file
170
third-party/vendor/swc_common/src/errors/styled_buffer.rs
vendored
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Code for creating styled buffers
|
||||
|
||||
use super::snippet::{Style, StyledString};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StyledBuffer {
|
||||
text: Vec<Vec<char>>,
|
||||
styles: Vec<Vec<Style>>,
|
||||
}
|
||||
|
||||
impl StyledBuffer {
|
||||
pub fn new() -> StyledBuffer {
|
||||
StyledBuffer {
|
||||
text: vec![],
|
||||
styles: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_tabs(&mut self) {
|
||||
for (line_pos, line) in self.text.iter_mut().enumerate() {
|
||||
let mut tab_pos = vec![];
|
||||
for (pos, c) in line.iter().enumerate() {
|
||||
if *c == '\t' {
|
||||
tab_pos.push(pos);
|
||||
}
|
||||
}
|
||||
// start with the tabs at the end of the line to replace them with 4 space chars
|
||||
for pos in tab_pos.iter().rev() {
|
||||
assert_eq!(line.remove(*pos), '\t');
|
||||
// fix the position of the style to match up after replacing the tabs
|
||||
let s = self.styles[line_pos].remove(*pos);
|
||||
for _ in 0..4 {
|
||||
line.insert(*pos, ' ');
|
||||
self.styles[line_pos].insert(*pos, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&mut self) -> Vec<Vec<StyledString>> {
|
||||
let mut output: Vec<Vec<StyledString>> = vec![];
|
||||
let mut styled_vec: Vec<StyledString> = vec![];
|
||||
|
||||
// before we render, replace tabs with spaces
|
||||
self.replace_tabs();
|
||||
|
||||
for (row, row_style) in self.text.iter().zip(&self.styles) {
|
||||
let mut current_style = Style::NoStyle;
|
||||
let mut current_text = String::new();
|
||||
|
||||
for (&c, &s) in row.iter().zip(row_style) {
|
||||
if s != current_style {
|
||||
if !current_text.is_empty() {
|
||||
styled_vec.push(StyledString {
|
||||
text: current_text,
|
||||
style: current_style,
|
||||
});
|
||||
}
|
||||
current_style = s;
|
||||
current_text = String::new();
|
||||
}
|
||||
current_text.push(c);
|
||||
}
|
||||
if !current_text.is_empty() {
|
||||
styled_vec.push(StyledString {
|
||||
text: current_text,
|
||||
style: current_style,
|
||||
});
|
||||
}
|
||||
|
||||
// We're done with the row, push and keep going
|
||||
output.push(styled_vec);
|
||||
|
||||
styled_vec = vec![];
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
fn ensure_lines(&mut self, line: usize) {
|
||||
while line >= self.text.len() {
|
||||
self.text.push(vec![]);
|
||||
self.styles.push(vec![]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
|
||||
self.ensure_lines(line);
|
||||
if col < self.text[line].len() {
|
||||
self.text[line][col] = chr;
|
||||
self.styles[line][col] = style;
|
||||
} else {
|
||||
let mut i = self.text[line].len();
|
||||
while i < col {
|
||||
self.text[line].push(' ');
|
||||
self.styles[line].push(Style::NoStyle);
|
||||
i += 1;
|
||||
}
|
||||
self.text[line].push(chr);
|
||||
self.styles[line].push(style);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
|
||||
let mut n = col;
|
||||
for c in string.chars() {
|
||||
self.putc(line, n, c, style);
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
|
||||
self.ensure_lines(line);
|
||||
let string_len = string.len();
|
||||
|
||||
// Push the old content over to make room for new content
|
||||
for _ in 0..string_len {
|
||||
self.styles[line].insert(0, Style::NoStyle);
|
||||
self.text[line].insert(0, ' ');
|
||||
}
|
||||
|
||||
self.puts(line, 0, string, style);
|
||||
}
|
||||
|
||||
pub fn append(&mut self, line: usize, string: &str, style: Style) {
|
||||
if line >= self.text.len() {
|
||||
self.puts(line, 0, string, style);
|
||||
} else {
|
||||
let col = self.text[line].len();
|
||||
self.puts(line, col, string, style);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_lines(&self) -> usize {
|
||||
self.text.len()
|
||||
}
|
||||
|
||||
pub fn set_style_range(
|
||||
&mut self,
|
||||
line: usize,
|
||||
col_start: usize,
|
||||
col_end: usize,
|
||||
style: Style,
|
||||
overwrite: bool,
|
||||
) {
|
||||
for col in col_start..col_end {
|
||||
self.set_style(line, col, style, overwrite);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
|
||||
if let Some(ref mut line) = self.styles.get_mut(line) {
|
||||
if let Some(s) = line.get_mut(col) {
|
||||
if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
|
||||
*s = style;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
75
third-party/vendor/swc_common/src/errors/tests.rs
vendored
Normal file
75
third-party/vendor/swc_common/src/errors/tests.rs
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
use super::*;
|
||||
use crate::{FileLoader, FilePathMapping, SourceMap};
|
||||
use std::{
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use sync::Lrc;
|
||||
use BytePos;
|
||||
use Span;
|
||||
|
||||
struct MyFileLoader;
|
||||
impl FileLoader for MyFileLoader {
|
||||
/// Query the existence of a file.
|
||||
fn file_exists(&self, path: &Path) -> bool {
|
||||
println!("File exists?: {}", path.display());
|
||||
true
|
||||
}
|
||||
|
||||
/// Return an absolute path to a file, if possible.
|
||||
fn abs_path(&self, _path: &Path) -> Option<PathBuf> {
|
||||
Some("/tmp.js".into())
|
||||
}
|
||||
|
||||
/// Read the contents of an UTF-8 file into memory.
|
||||
fn read_file(&self, _path: &Path) -> io::Result<String> {
|
||||
Ok("
|
||||
function foo() {
|
||||
with (window) {
|
||||
|
||||
}
|
||||
}"
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let cm = SourceMap::with_file_loader(box MyFileLoader, FilePathMapping::empty());
|
||||
let file_map = cm
|
||||
.load_file(Path::new("tmp.js").into())
|
||||
.expect("failed to load tmp.js");
|
||||
println!(
|
||||
"File (start={},end={})",
|
||||
file_map.start_pos.0, file_map.end_pos.0
|
||||
);
|
||||
let start_pos = file_map.start_pos + BytePos(1);
|
||||
let end_pos = file_map.end_pos - BytePos(1);
|
||||
let full = Span::new(start_pos, end_pos, Default::default());
|
||||
|
||||
let handler = Handler::with_tty_emitter(ColorConfig::Always, false, false, Some(Arc::new(cm)));
|
||||
|
||||
::syntax_pos::GLOBALS.set(&::syntax_pos::Globals::new(), || {
|
||||
DiagnosticBuilder::new_with_code(
|
||||
&handler,
|
||||
Error,
|
||||
Some(DiagnosticId::Error("ABCDE".into())),
|
||||
"Test span_label",
|
||||
)
|
||||
.span(full)
|
||||
.emit();
|
||||
|
||||
DiagnosticBuilder::new_with_code(
|
||||
&handler,
|
||||
super::Warning,
|
||||
Some(DiagnosticId::Lint("WITH_STMT".into())),
|
||||
"Lint: With statement",
|
||||
)
|
||||
.span(Span::new(
|
||||
start_pos + BytePos(21),
|
||||
start_pos + BytePos(25),
|
||||
Default::default(),
|
||||
))
|
||||
.emit();
|
||||
})
|
||||
}
|
||||
434
third-party/vendor/swc_common/src/input.rs
vendored
Normal file
434
third-party/vendor/swc_common/src/input.rs
vendored
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
use std::str;
|
||||
|
||||
use debug_unreachable::debug_unreachable;
|
||||
|
||||
use crate::syntax_pos::{BytePos, SourceFile};
|
||||
|
||||
pub type SourceFileInput<'a> = StringInput<'a>;
|
||||
|
||||
/// Implementation of [Input].
|
||||
#[derive(Clone)]
|
||||
pub struct StringInput<'a> {
|
||||
start_pos_of_iter: BytePos,
|
||||
last_pos: BytePos,
|
||||
/// Current cursor
|
||||
iter: str::CharIndices<'a>,
|
||||
orig: &'a str,
|
||||
/// Original start position.
|
||||
orig_start: BytePos,
|
||||
}
|
||||
|
||||
impl<'a> StringInput<'a> {
|
||||
/// `start` and `end` can be arbitrary value, but start should be less than
|
||||
/// or equal to end.
|
||||
///
|
||||
///
|
||||
/// `swc` get this value from [SourceMap] because code generator depends on
|
||||
/// some methods of [SourceMap].
|
||||
/// If you are not going to use methods from
|
||||
/// [SourceMap], you may use any value.
|
||||
pub fn new(src: &'a str, start: BytePos, end: BytePos) -> Self {
|
||||
assert!(start <= end);
|
||||
|
||||
StringInput {
|
||||
start_pos_of_iter: start,
|
||||
last_pos: start,
|
||||
orig: src,
|
||||
iter: src.char_indices(),
|
||||
orig_start: start,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.iter.as_str()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bump_bytes(&mut self, n: usize) {
|
||||
unsafe {
|
||||
// Safety: We only proceed, not go back.
|
||||
self.reset_to(self.last_pos + BytePos(n as u32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an [Input] from [SourceFile]. This is an alias for
|
||||
///
|
||||
/// ```ignore
|
||||
/// StringInput::new(&fm.src, fm.start_pos, fm.end_pos)
|
||||
/// ```
|
||||
impl<'a> From<&'a SourceFile> for StringInput<'a> {
|
||||
fn from(fm: &'a SourceFile) -> Self {
|
||||
StringInput::new(&fm.src, fm.start_pos, fm.end_pos)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Input for StringInput<'a> {
|
||||
#[inline]
|
||||
fn cur(&mut self) -> Option<char> {
|
||||
self.iter.clone().next().map(|i| i.1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn peek(&mut self) -> Option<char> {
|
||||
self.iter.clone().nth(1).map(|i| i.1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn peek_ahead(&mut self) -> Option<char> {
|
||||
self.iter.clone().nth(2).map(|i| i.1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn bump(&mut self) {
|
||||
if let Some((i, c)) = self.iter.next() {
|
||||
self.last_pos = self.start_pos_of_iter + BytePos((i + c.len_utf8()) as u32);
|
||||
} else {
|
||||
unsafe {
|
||||
debug_unreachable!("bump should not be called when cur() == None");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cur_as_ascii(&mut self) -> Option<u8> {
|
||||
let first_byte = *self.as_str().as_bytes().first()?;
|
||||
if first_byte <= 0x7f {
|
||||
Some(first_byte)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_at_start(&self) -> bool {
|
||||
self.orig_start == self.last_pos
|
||||
}
|
||||
|
||||
/// TODO(kdy1): Remove this?
|
||||
#[inline]
|
||||
fn cur_pos(&mut self) -> BytePos {
|
||||
self.last_pos
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn last_pos(&self) -> BytePos {
|
||||
self.last_pos
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn slice(&mut self, start: BytePos, end: BytePos) -> &str {
|
||||
debug_assert!(start <= end, "Cannot slice {:?}..{:?}", start, end);
|
||||
let s = self.orig;
|
||||
|
||||
let start_idx = (start - self.orig_start).0 as usize;
|
||||
let end_idx = (end - self.orig_start).0 as usize;
|
||||
|
||||
debug_assert!(end_idx <= s.len());
|
||||
|
||||
let ret = unsafe { s.get_unchecked(start_idx..end_idx) };
|
||||
|
||||
self.iter = unsafe { s.get_unchecked(end_idx..) }.char_indices();
|
||||
self.last_pos = end;
|
||||
self.start_pos_of_iter = end;
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
fn uncons_while<F>(&mut self, mut pred: F) -> &str
|
||||
where
|
||||
F: FnMut(char) -> bool,
|
||||
{
|
||||
let s = self.iter.as_str();
|
||||
let mut last = 0;
|
||||
|
||||
for (i, c) in s.char_indices() {
|
||||
if pred(c) {
|
||||
last = i + c.len_utf8();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
debug_assert!(last <= s.len());
|
||||
let ret = unsafe { s.get_unchecked(..last) };
|
||||
|
||||
self.last_pos = self.last_pos + BytePos(last as _);
|
||||
self.start_pos_of_iter = self.last_pos;
|
||||
self.iter = unsafe { s.get_unchecked(last..) }.char_indices();
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
fn find<F>(&mut self, mut pred: F) -> Option<BytePos>
|
||||
where
|
||||
F: FnMut(char) -> bool,
|
||||
{
|
||||
let s = self.iter.as_str();
|
||||
let mut last = 0;
|
||||
|
||||
for (i, c) in s.char_indices() {
|
||||
if pred(c) {
|
||||
last = i + c.len_utf8();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if last == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
debug_assert!(last <= s.len());
|
||||
|
||||
self.last_pos = self.last_pos + BytePos(last as _);
|
||||
self.start_pos_of_iter = self.last_pos;
|
||||
self.iter = unsafe { s.get_unchecked(last..) }.char_indices();
|
||||
|
||||
Some(self.last_pos)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn reset_to(&mut self, to: BytePos) {
|
||||
let orig = self.orig;
|
||||
let idx = (to - self.orig_start).0 as usize;
|
||||
|
||||
debug_assert!(idx <= orig.len());
|
||||
let s = unsafe { orig.get_unchecked(idx..) };
|
||||
self.iter = s.char_indices();
|
||||
self.start_pos_of_iter = to;
|
||||
self.last_pos = to;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_byte(&mut self, c: u8) -> bool {
|
||||
self.iter
|
||||
.as_str()
|
||||
.as_bytes()
|
||||
.first()
|
||||
.map(|b| *b == c)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_str(&self, s: &str) -> bool {
|
||||
self.as_str().starts_with(s)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn eat_byte(&mut self, c: u8) -> bool {
|
||||
if self.is_byte(c) {
|
||||
if let Some((i, _)) = self.iter.next() {
|
||||
self.last_pos = self.start_pos_of_iter + BytePos((i + 1) as u32);
|
||||
} else {
|
||||
unsafe {
|
||||
debug_unreachable!(
|
||||
"We can't enter here as we already checked the state using `is_byte`"
|
||||
)
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Input: Clone {
|
||||
fn cur(&mut self) -> Option<char>;
|
||||
fn peek(&mut self) -> Option<char>;
|
||||
fn peek_ahead(&mut self) -> Option<char>;
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// This should be called only when `cur()` returns `Some`. i.e.
|
||||
/// when the Input is not empty.
|
||||
unsafe fn bump(&mut self);
|
||||
|
||||
/// Returns [None] if it's end of input **or** current character is not an
|
||||
/// ascii character.
|
||||
#[inline]
|
||||
fn cur_as_ascii(&mut self) -> Option<u8> {
|
||||
self.cur().and_then(|i| {
|
||||
if i.is_ascii() {
|
||||
return Some(i as u8);
|
||||
}
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
fn is_at_start(&self) -> bool;
|
||||
|
||||
fn cur_pos(&mut self) -> BytePos;
|
||||
|
||||
fn last_pos(&self) -> BytePos;
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// - start should be less than or equal to end.
|
||||
/// - start and end should be in the valid range of input.
|
||||
unsafe fn slice(&mut self, start: BytePos, end: BytePos) -> &str;
|
||||
|
||||
/// Takes items from stream, testing each one with predicate. returns the
|
||||
/// range of items which passed predicate.
|
||||
fn uncons_while<F>(&mut self, f: F) -> &str
|
||||
where
|
||||
F: FnMut(char) -> bool;
|
||||
|
||||
/// This method modifies [last_pos()] and [cur_pos()].
|
||||
fn find<F>(&mut self, f: F) -> Option<BytePos>
|
||||
where
|
||||
F: FnMut(char) -> bool;
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// - `to` be in the valid range of input.
|
||||
unsafe fn reset_to(&mut self, to: BytePos);
|
||||
|
||||
/// Implementors can override the method to make it faster.
|
||||
///
|
||||
/// `c` must be ASCII.
|
||||
#[inline]
|
||||
#[allow(clippy::wrong_self_convention)]
|
||||
fn is_byte(&mut self, c: u8) -> bool {
|
||||
match self.cur() {
|
||||
Some(ch) => ch == c as char,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementors can override the method to make it faster.
|
||||
///
|
||||
/// `s` must be ASCII only.
|
||||
fn is_str(&self, s: &str) -> bool;
|
||||
|
||||
/// Implementors can override the method to make it faster.
|
||||
///
|
||||
/// `c` must be ASCII.
|
||||
#[inline]
|
||||
fn eat_byte(&mut self, c: u8) -> bool {
|
||||
if self.is_byte(c) {
|
||||
unsafe {
|
||||
// Safety: We are sure that the input is not empty
|
||||
self.bump();
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::*;
|
||||
use crate::{FileName, FilePathMapping, SourceMap};
|
||||
|
||||
fn with_test_sess<F>(src: &str, f: F)
|
||||
where
|
||||
F: FnOnce(StringInput<'_>),
|
||||
{
|
||||
let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
let fm = cm.new_source_file(FileName::Real("testing".into()), src.into());
|
||||
|
||||
f((&*fm).into())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn src_input_slice_1() {
|
||||
with_test_sess("foo/d", |mut i| {
|
||||
assert_eq!(unsafe { i.slice(BytePos(1), BytePos(2)) }, "f");
|
||||
assert_eq!(i.last_pos, BytePos(2));
|
||||
assert_eq!(i.start_pos_of_iter, BytePos(2));
|
||||
assert_eq!(i.cur(), Some('o'));
|
||||
|
||||
assert_eq!(unsafe { i.slice(BytePos(2), BytePos(4)) }, "oo");
|
||||
assert_eq!(unsafe { i.slice(BytePos(1), BytePos(4)) }, "foo");
|
||||
assert_eq!(i.last_pos, BytePos(4));
|
||||
assert_eq!(i.start_pos_of_iter, BytePos(4));
|
||||
assert_eq!(i.cur(), Some('/'));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn src_input_reset_to_1() {
|
||||
with_test_sess("load", |mut i| {
|
||||
assert_eq!(unsafe { i.slice(BytePos(1), BytePos(3)) }, "lo");
|
||||
assert_eq!(i.last_pos, BytePos(3));
|
||||
assert_eq!(i.start_pos_of_iter, BytePos(3));
|
||||
assert_eq!(i.cur(), Some('a'));
|
||||
unsafe { i.reset_to(BytePos(1)) };
|
||||
|
||||
assert_eq!(i.cur(), Some('l'));
|
||||
assert_eq!(i.last_pos, BytePos(1));
|
||||
assert_eq!(i.start_pos_of_iter, BytePos(1));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn src_input_smoke_01() {
|
||||
with_test_sess("foo/d", |mut i| {
|
||||
assert_eq!(i.cur_pos(), BytePos(1));
|
||||
assert_eq!(i.last_pos, BytePos(1));
|
||||
assert_eq!(i.start_pos_of_iter, BytePos(1));
|
||||
assert_eq!(i.uncons_while(|c| c.is_alphabetic()), "foo");
|
||||
|
||||
// assert_eq!(i.cur_pos(), BytePos(4));
|
||||
assert_eq!(i.last_pos, BytePos(4));
|
||||
assert_eq!(i.start_pos_of_iter, BytePos(4));
|
||||
assert_eq!(i.cur(), Some('/'));
|
||||
|
||||
unsafe {
|
||||
i.bump();
|
||||
}
|
||||
assert_eq!(i.last_pos, BytePos(5));
|
||||
assert_eq!(i.cur(), Some('d'));
|
||||
|
||||
unsafe {
|
||||
i.bump();
|
||||
}
|
||||
assert_eq!(i.last_pos, BytePos(6));
|
||||
assert_eq!(i.cur(), None);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn src_input_find_01() {
|
||||
with_test_sess("foo/d", |mut i| {
|
||||
assert_eq!(i.cur_pos(), BytePos(1));
|
||||
assert_eq!(i.last_pos, BytePos(1));
|
||||
assert_eq!(i.start_pos_of_iter, BytePos(1));
|
||||
|
||||
assert_eq!(i.find(|c| c == '/'), Some(BytePos(5)));
|
||||
assert_eq!(i.start_pos_of_iter, BytePos(5));
|
||||
assert_eq!(i.last_pos, BytePos(5));
|
||||
assert_eq!(i.cur(), Some('d'));
|
||||
});
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn src_input_smoke_02() {
|
||||
// let _ = crate::with_test_sess("℘℘/℘℘", | mut i| {
|
||||
// assert_eq!(i.iter.as_str(), "℘℘/℘℘");
|
||||
// assert_eq!(i.cur_pos(), BytePos(0));
|
||||
// assert_eq!(i.last_pos, BytePos(0));
|
||||
// assert_eq!(i.start_pos, BytePos(0));
|
||||
// assert_eq!(i.uncons_while(|c| c.is_ident_part()), "℘℘");
|
||||
//
|
||||
// assert_eq!(i.iter.as_str(), "/℘℘");
|
||||
// assert_eq!(i.last_pos, BytePos(6));
|
||||
// assert_eq!(i.start_pos, BytePos(6));
|
||||
// assert_eq!(i.cur(), Some('/'));
|
||||
// i.bump();
|
||||
// assert_eq!(i.last_pos, BytePos(7));
|
||||
// assert_eq!(i.start_pos, BytePos(6));
|
||||
//
|
||||
// assert_eq!(i.iter.as_str(), "℘℘");
|
||||
// assert_eq!(i.uncons_while(|c| c.is_ident_part()), "℘℘");
|
||||
// assert_eq!(i.last_pos, BytePos(13));
|
||||
// assert_eq!(i.start_pos, BytePos(13));
|
||||
//
|
||||
// Ok(())
|
||||
// });
|
||||
// }
|
||||
}
|
||||
45
third-party/vendor/swc_common/src/iter.rs
vendored
Normal file
45
third-party/vendor/swc_common/src/iter.rs
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/// Copied from https://users.rust-lang.org/t/iterator-need-to-identify-the-last-element/8836/3
|
||||
pub trait IdentifyLast: Iterator + Sized {
|
||||
fn identify_last(self) -> Iter<Self>;
|
||||
}
|
||||
|
||||
impl<It> IdentifyLast for It
|
||||
where
|
||||
It: Iterator,
|
||||
{
|
||||
fn identify_last(mut self) -> Iter<Self> {
|
||||
let e = self.next();
|
||||
Iter {
|
||||
iter: self,
|
||||
buffer: e,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Iter<It>
|
||||
where
|
||||
It: Iterator,
|
||||
{
|
||||
iter: It,
|
||||
buffer: Option<It::Item>,
|
||||
}
|
||||
|
||||
impl<It> Iterator for Iter<It>
|
||||
where
|
||||
It: Iterator,
|
||||
{
|
||||
type Item = (bool, It::Item);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.buffer.take() {
|
||||
None => None,
|
||||
Some(e) => match self.iter.next() {
|
||||
None => Some((true, e)),
|
||||
Some(f) => {
|
||||
self.buffer = Some(f);
|
||||
Some((false, e))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
92
third-party/vendor/swc_common/src/lib.rs
vendored
Normal file
92
third-party/vendor/swc_common/src/lib.rs
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
//! Utilities for the swc project
|
||||
//!
|
||||
//!
|
||||
//! # Cargo features
|
||||
//!
|
||||
//! ## `tty-emitter`
|
||||
//!
|
||||
//! Adds default implementation of Emitter.
|
||||
//! Enabling this feature will add tty-related dependencies.
|
||||
//!
|
||||
//! ## `sourcemap`
|
||||
//!
|
||||
//! Adds methods to generate web sourcemap.
|
||||
//!
|
||||
//! ## `plugin-base`
|
||||
//!
|
||||
//! Base mode for plugins, which can be enabled by `plugin-mode` or `plugin-rt`.
|
||||
//!
|
||||
//! This mode creates a trait which can be used to override `swc_common` itself.
|
||||
//!
|
||||
//! ## `plugin-rt`
|
||||
//!
|
||||
//! Creates an implementation for the plugin trait. This implements simply
|
||||
//! invokes thread-locals declared in `swc_common`.
|
||||
//!
|
||||
//! ## `plugin-mode`
|
||||
//!
|
||||
//! Allows replacing operations related to thread-local variables with a trait.
|
||||
//!
|
||||
//!
|
||||
//! ## `ahash`
|
||||
//!
|
||||
//! Use `ahash` instead of `rustc_hash` for `AHashMap` and `AHashSet`.
|
||||
#![deny(clippy::all)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub use ast_node::{ast_node, ast_serde, DeserializeEnum, Spanned};
|
||||
pub use from_variant::FromVariant;
|
||||
pub use swc_eq_ignore_macros::{EqIgnoreSpan, TypeEq};
|
||||
pub use swc_visit::chain;
|
||||
|
||||
pub use self::{
|
||||
eq::{EqIgnoreSpan, TypeEq},
|
||||
errors::{SourceMapper, SourceMapperDyn},
|
||||
pos::{
|
||||
hygiene, BytePos, CharPos, FileName, Globals, Loc, LocWithOpt, Mark, MultiSpan, SourceFile,
|
||||
SourceFileAndBytePos, SourceFileAndLine, Span, SpanLinesError, Spanned, SyntaxContext,
|
||||
DUMMY_SP, GLOBALS, NO_EXPANSION,
|
||||
},
|
||||
source_map::{FileLines, FileLoader, FilePathMapping, SourceMap, SpanSnippetError},
|
||||
syntax_pos::LineCol,
|
||||
};
|
||||
#[doc(hidden)]
|
||||
pub mod private;
|
||||
|
||||
/// A trait for ast nodes.
|
||||
pub trait AstNode: Debug + PartialEq + Clone + Spanned {
|
||||
const TYPE: &'static str;
|
||||
}
|
||||
|
||||
pub mod collections;
|
||||
pub mod comments;
|
||||
mod eq;
|
||||
pub mod errors;
|
||||
pub mod input;
|
||||
pub mod iter;
|
||||
pub mod pass;
|
||||
pub mod plugin;
|
||||
mod pos;
|
||||
mod rustc_data_structures;
|
||||
pub mod serializer;
|
||||
pub mod source_map;
|
||||
pub mod sync;
|
||||
mod syntax_pos;
|
||||
pub mod util;
|
||||
|
||||
#[cfg(all(not(debug_assertions), feature = "plugin-rt", feature = "plugin-mode"))]
|
||||
compile_error!("You can't enable `plugin-rt` and `plugin-mode` at the same time");
|
||||
|
||||
/// Warning: The particular implementation of serialization and deserialization
|
||||
/// of the ast nodes may change in the future, and so these types would be
|
||||
/// removed. It's safe to say they will be serializable in some form or another,
|
||||
/// but not necessarily with these specific types underlying the implementation.
|
||||
/// As such, *use these types at your own risk*.
|
||||
#[cfg(feature = "rkyv-impl")]
|
||||
#[doc(hidden)]
|
||||
pub use self::syntax_pos::{
|
||||
ArchivedBytePos, ArchivedCharPos, ArchivedFileName, ArchivedMultiSpan, ArchivedSourceFile,
|
||||
ArchivedSourceFileAndBytePos, ArchivedSpan, ArchivedSpanLinesError, ArchivedSpanSnippetError,
|
||||
};
|
||||
32
third-party/vendor/swc_common/src/pass.rs
vendored
Normal file
32
third-party/vendor/swc_common/src/pass.rs
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
//! This module reexports items from `swc_visit` with some swc-specific traits.
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub use swc_visit::*;
|
||||
|
||||
/// A named compiler pass.
|
||||
pub trait CompilerPass {
|
||||
///
|
||||
/// - name should follow hyphen-case.
|
||||
/// - an implementation should return same name
|
||||
fn name() -> Cow<'static, str>;
|
||||
}
|
||||
|
||||
impl<V> CompilerPass for Repeat<V>
|
||||
where
|
||||
V: CompilerPass + Repeated,
|
||||
{
|
||||
fn name() -> Cow<'static, str> {
|
||||
Cow::Owned(format!("repeat({})", V::name()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> CompilerPass for AndThen<A, B>
|
||||
where
|
||||
A: CompilerPass,
|
||||
B: CompilerPass,
|
||||
{
|
||||
fn name() -> Cow<'static, str> {
|
||||
Cow::Owned(format!("{} -> {}", A::name(), B::name()))
|
||||
}
|
||||
}
|
||||
17
third-party/vendor/swc_common/src/plugin/diagnostics.rs
vendored
Normal file
17
third-party/vendor/swc_common/src/plugin/diagnostics.rs
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/// A serializable, wrapped struct for the diagnostics information
|
||||
/// included in plugin binaries.
|
||||
/// TODO: Must implement bytecheck with forward-compatible schema changes to
|
||||
/// prevent handshake failure.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct PluginCorePkgDiagnostics {
|
||||
pub pkg_version: String,
|
||||
pub git_sha: String,
|
||||
pub cargo_features: String,
|
||||
pub ast_schema_version: u32,
|
||||
}
|
||||
67
third-party/vendor/swc_common/src/plugin/metadata.rs
vendored
Normal file
67
third-party/vendor/swc_common/src/plugin/metadata.rs
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
use std::env;
|
||||
|
||||
use crate::collections::AHashMap;
|
||||
|
||||
/// Indexable key to the metadata context for a transform plugin, avoiding
|
||||
/// serialization & allocation to the host by using incremental number.
|
||||
/// TransformPluginMetadataContext does not implement Index trait, instead
|
||||
/// host does manual matching to corresponding value.
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum TransformPluginMetadataContextKind {
|
||||
// This value always should increase, even if some keys are removed in the
|
||||
// future.
|
||||
Filename = 1,
|
||||
Env = 2,
|
||||
Cwd = 3,
|
||||
}
|
||||
|
||||
impl From<u32> for TransformPluginMetadataContextKind {
|
||||
fn from(key: u32) -> TransformPluginMetadataContextKind {
|
||||
match key {
|
||||
1 => TransformPluginMetadataContextKind::Filename,
|
||||
2 => TransformPluginMetadataContextKind::Env,
|
||||
3 => TransformPluginMetadataContextKind::Cwd,
|
||||
_ => panic!("Invalid TransformPluginMetadataContextKind key"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Host side metadata context plugin may need to access.
|
||||
/// This is a global context - any plugin in single transform will have same
|
||||
/// values.
|
||||
pub struct TransformPluginMetadataContext {
|
||||
/// The path of the file being processed. This includes all of the path as
|
||||
/// much as possible.
|
||||
pub filename: Option<String>,
|
||||
/// The current environment resolved as process.env.SWC_ENV ||
|
||||
/// process.env.NODE_ENV || "development"
|
||||
pub env: String,
|
||||
/// The current working directory.
|
||||
pub cwd: Option<String>,
|
||||
pub experimental: AHashMap<String, String>,
|
||||
}
|
||||
|
||||
impl TransformPluginMetadataContext {
|
||||
pub fn new(
|
||||
filename: Option<String>,
|
||||
env: String,
|
||||
experimental: Option<AHashMap<String, String>>,
|
||||
) -> Self {
|
||||
TransformPluginMetadataContext {
|
||||
filename,
|
||||
env,
|
||||
cwd: env::current_dir()
|
||||
.map(|cwd| cwd.as_path().to_string_lossy().to_string())
|
||||
.ok(),
|
||||
experimental: experimental.unwrap_or_default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &TransformPluginMetadataContextKind) -> Option<String> {
|
||||
match key {
|
||||
TransformPluginMetadataContextKind::Filename => self.filename.clone(),
|
||||
TransformPluginMetadataContextKind::Env => Some(self.env.clone()),
|
||||
TransformPluginMetadataContextKind::Cwd => self.cwd.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
27
third-party/vendor/swc_common/src/plugin/mod.rs
vendored
Normal file
27
third-party/vendor/swc_common/src/plugin/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
pub mod diagnostics;
|
||||
pub mod metadata;
|
||||
#[cfg(feature = "__plugin")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "__plugin")))]
|
||||
pub mod serialized;
|
||||
|
||||
/**
|
||||
* Compile-time version constant for the AST struct schema's version.
|
||||
*
|
||||
* NOTE: this is for PARTIAL compatibility only, supporting if AST struct
|
||||
* adds new properties without changing / removing existing properties.
|
||||
*
|
||||
* - When adding a new properties to the AST struct:
|
||||
* 1. Create a new feature flag in cargo.toml
|
||||
* 2. Create a new schema version with new feature flag.
|
||||
* 3. Create a new AST struct with compile time feature flag with newly
|
||||
* added properties. Previous struct should remain with existing feature
|
||||
* flag, or add previous latest feature flag.
|
||||
*
|
||||
* - When removing, or changing existing properties in the AST struct: TBD
|
||||
*/
|
||||
#[cfg(feature = "plugin_transform_schema_v1")]
|
||||
pub const PLUGIN_TRANSFORM_AST_SCHEMA_VERSION: u32 = 1;
|
||||
|
||||
// Reserved for the testing purpose.
|
||||
#[cfg(feature = "plugin_transform_schema_vtest")]
|
||||
pub const PLUGIN_TRANSFORM_AST_SCHEMA_VERSION: u32 = u32::MAX - 1;
|
||||
151
third-party/vendor/swc_common/src/plugin/serialized.rs
vendored
Normal file
151
third-party/vendor/swc_common/src/plugin/serialized.rs
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
use std::any::type_name;
|
||||
|
||||
use anyhow::Error;
|
||||
#[cfg(feature = "__rkyv")]
|
||||
use rkyv::Deserialize;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
#[cfg_attr(
|
||||
feature = "__plugin",
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "__plugin", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "__plugin", archive_attr(repr(u32)))]
|
||||
/// Enum for possible errors while running transform via plugin.
|
||||
/// This error indicates internal operation failure either in plugin_runner
|
||||
/// or plugin_macro. Plugin's transform fn itself does not allow to return
|
||||
/// error - instead it should use provided `handler` to emit corresponding error
|
||||
/// to the host.
|
||||
pub enum PluginError {
|
||||
/// Occurs when failed to convert size passed from host / guest into usize
|
||||
/// or similar for the conversion. This is an internal error rasied via
|
||||
/// plugin_macro, normally plugin author should not raise this manually.
|
||||
SizeInteropFailure(String),
|
||||
/// Occurs when failed to reconstruct a struct from `Serialized`.
|
||||
Deserialize(String),
|
||||
/// Occurs when failed to serialize a struct into `Serialized`.
|
||||
/// Unlike deserialize error, this error cannot forward any context for the
|
||||
/// raw bytes: when serialize failed, there's nothing we can pass between
|
||||
/// runtime.
|
||||
Serialize(String),
|
||||
}
|
||||
|
||||
/// Wraps internal representation of serialized data for exchanging data between
|
||||
/// plugin to the host. Consumers should not rely on specific details of byte
|
||||
/// format struct contains: it is strict implementation detail which can
|
||||
/// change anytime.
|
||||
pub struct PluginSerializedBytes {
|
||||
pub(crate) field: rkyv::AlignedVec,
|
||||
}
|
||||
|
||||
#[cfg(feature = "__plugin")]
|
||||
impl PluginSerializedBytes {
|
||||
/**
|
||||
* Constructs an instance from already serialized byte
|
||||
* slices.
|
||||
*/
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn from_slice(bytes: &[u8]) -> PluginSerializedBytes {
|
||||
let mut field = rkyv::AlignedVec::new();
|
||||
field.extend_from_slice(bytes);
|
||||
PluginSerializedBytes { field }
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance from versioned struct by serializing it.
|
||||
*
|
||||
* This is sort of mimic TryFrom behavior, since we can't use generic
|
||||
* to implement TryFrom trait
|
||||
*/
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn try_serialize<W>(t: &VersionedSerializable<W>) -> Result<Self, Error>
|
||||
where
|
||||
W: rkyv::Serialize<rkyv::ser::serializers::AllocSerializer<512>>,
|
||||
{
|
||||
rkyv::to_bytes::<_, 512>(t)
|
||||
.map(|field| PluginSerializedBytes { field })
|
||||
.map_err(|err| match err {
|
||||
rkyv::ser::serializers::CompositeSerializerError::SerializerError(e) => e.into(),
|
||||
rkyv::ser::serializers::CompositeSerializerError::ScratchSpaceError(_e) => {
|
||||
Error::msg("AllocScratchError")
|
||||
}
|
||||
rkyv::ser::serializers::CompositeSerializerError::SharedError(_e) => {
|
||||
Error::msg("SharedSerializeMapError")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal fn to constructs an instance from raw bytes ptr.
|
||||
*/
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||
pub fn from_raw_ptr(
|
||||
raw_allocated_ptr: *const u8,
|
||||
raw_allocated_ptr_len: usize,
|
||||
) -> PluginSerializedBytes {
|
||||
let raw_ptr_bytes =
|
||||
unsafe { std::slice::from_raw_parts(raw_allocated_ptr, raw_allocated_ptr_len) };
|
||||
|
||||
PluginSerializedBytes::from_slice(raw_ptr_bytes)
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
self.field.as_slice()
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> (*const u8, usize) {
|
||||
(self.field.as_ptr(), self.field.len())
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "info", skip_all)]
|
||||
pub fn deserialize<W>(&self) -> Result<VersionedSerializable<W>, Error>
|
||||
where
|
||||
W: rkyv::Archive,
|
||||
W::Archived: rkyv::Deserialize<W, rkyv::de::deserializers::SharedDeserializeMap>,
|
||||
{
|
||||
use anyhow::Context;
|
||||
|
||||
let archived = unsafe { rkyv::archived_root::<VersionedSerializable<W>>(&self.field[..]) };
|
||||
|
||||
archived
|
||||
.deserialize(&mut rkyv::de::deserializers::SharedDeserializeMap::new())
|
||||
.with_context(|| format!("failed to deserialize `{}`", type_name::<W>()))
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper type for the structures to be passed into plugins
|
||||
/// serializes the contained value out-of-line so that newer
|
||||
/// versions can be viewed as the older version.
|
||||
///
|
||||
/// First field indicate version of struct type (schema). Any consumers like
|
||||
/// swc_plugin_macro can use this to validate compatiblility before attempt to
|
||||
/// serialize.
|
||||
#[cfg_attr(
|
||||
feature = "__plugin",
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[repr(transparent)]
|
||||
#[cfg_attr(feature = "__plugin", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "__plugin", archive_attr(repr(transparent)))]
|
||||
#[derive(Debug)]
|
||||
pub struct VersionedSerializable<T>(
|
||||
// [NOTE]: https://github.com/rkyv/rkyv/issues/373#issuecomment-1546360897
|
||||
//#[cfg_attr(feature = "__plugin", with(rkyv::with::AsBox))]
|
||||
pub T,
|
||||
);
|
||||
|
||||
impl<T> VersionedSerializable<T> {
|
||||
pub fn new(value: T) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> &T {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
192
third-party/vendor/swc_common/src/pos.rs
vendored
Normal file
192
third-party/vendor/swc_common/src/pos.rs
vendored
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
use std::{borrow::Cow, rc::Rc, sync::Arc};
|
||||
|
||||
pub use crate::syntax_pos::{
|
||||
hygiene, BytePos, CharPos, FileName, Globals, Loc, LocWithOpt, Mark, MultiSpan, SourceFile,
|
||||
SourceFileAndBytePos, SourceFileAndLine, Span, SpanLinesError, SyntaxContext, DUMMY_SP,
|
||||
GLOBALS, NO_EXPANSION,
|
||||
};
|
||||
|
||||
///
|
||||
/// # Derive
|
||||
/// This trait can be derived with `#[derive(Spanned)]`.
|
||||
pub trait Spanned {
|
||||
/// Get span of `self`.
|
||||
fn span(&self) -> Span;
|
||||
|
||||
#[inline]
|
||||
fn span_lo(&self) -> BytePos {
|
||||
self.span().lo
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_hi(&self) -> BytePos {
|
||||
self.span().hi
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Spanned for Cow<'a, T>
|
||||
where
|
||||
T: Spanned + Clone,
|
||||
{
|
||||
#[inline]
|
||||
fn span(&self) -> Span {
|
||||
(**self).span()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_lo(&self) -> BytePos {
|
||||
(**self).span_lo()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_hi(&self) -> BytePos {
|
||||
(**self).span_hi()
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned for Span {
|
||||
#[inline(always)]
|
||||
fn span(&self) -> Span {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned for BytePos {
|
||||
/// Creates a new single-byte span.
|
||||
#[inline(always)]
|
||||
fn span(&self) -> Span {
|
||||
Span::new(*self, *self, Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Spanned for Option<S>
|
||||
where
|
||||
S: Spanned,
|
||||
{
|
||||
#[inline]
|
||||
fn span(&self) -> Span {
|
||||
match *self {
|
||||
Some(ref s) => s.span(),
|
||||
None => DUMMY_SP,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_lo(&self) -> BytePos {
|
||||
match *self {
|
||||
Some(ref s) => s.span_lo(),
|
||||
None => BytePos::DUMMY,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_hi(&self) -> BytePos {
|
||||
match *self {
|
||||
Some(ref s) => s.span_hi(),
|
||||
None => BytePos::DUMMY,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Spanned for Rc<S>
|
||||
where
|
||||
S: ?Sized + Spanned,
|
||||
{
|
||||
fn span(&self) -> Span {
|
||||
<S as Spanned>::span(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_lo(&self) -> BytePos {
|
||||
<S as Spanned>::span_lo(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_hi(&self) -> BytePos {
|
||||
<S as Spanned>::span_hi(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Spanned for Arc<S>
|
||||
where
|
||||
S: ?Sized + Spanned,
|
||||
{
|
||||
fn span(&self) -> Span {
|
||||
<S as Spanned>::span(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_lo(&self) -> BytePos {
|
||||
<S as Spanned>::span_lo(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_hi(&self) -> BytePos {
|
||||
<S as Spanned>::span_hi(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Spanned for Box<S>
|
||||
where
|
||||
S: ?Sized + Spanned,
|
||||
{
|
||||
fn span(&self) -> Span {
|
||||
<S as Spanned>::span(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_lo(&self) -> BytePos {
|
||||
<S as Spanned>::span_lo(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_hi(&self) -> BytePos {
|
||||
<S as Spanned>::span_hi(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> Spanned for &'a S
|
||||
where
|
||||
S: ?Sized + Spanned,
|
||||
{
|
||||
fn span(&self) -> Span {
|
||||
<S as Spanned>::span(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_lo(&self) -> BytePos {
|
||||
<S as Spanned>::span_lo(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn span_hi(&self) -> BytePos {
|
||||
<S as Spanned>::span_hi(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> Spanned for ::either::Either<A, B>
|
||||
where
|
||||
A: Spanned,
|
||||
B: Spanned,
|
||||
{
|
||||
fn span(&self) -> Span {
|
||||
match *self {
|
||||
::either::Either::Left(ref n) => n.span(),
|
||||
::either::Either::Right(ref n) => n.span(),
|
||||
}
|
||||
}
|
||||
|
||||
fn span_lo(&self) -> BytePos {
|
||||
match *self {
|
||||
::either::Either::Left(ref n) => n.span_lo(),
|
||||
::either::Either::Right(ref n) => n.span_lo(),
|
||||
}
|
||||
}
|
||||
|
||||
fn span_hi(&self) -> BytePos {
|
||||
match *self {
|
||||
::either::Either::Left(ref n) => n.span_hi(),
|
||||
::either::Either::Right(ref n) => n.span_hi(),
|
||||
}
|
||||
}
|
||||
}
|
||||
3
third-party/vendor/swc_common/src/private/mod.rs
vendored
Normal file
3
third-party/vendor/swc_common/src/private/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
//! This module is private module and can be changed without notice.
|
||||
|
||||
pub use serde::__private as serde;
|
||||
2
third-party/vendor/swc_common/src/rustc_data_structures.rs
vendored
Normal file
2
third-party/vendor/swc_common/src/rustc_data_structures.rs
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#![allow(clippy::all)]
|
||||
pub mod stable_hasher;
|
||||
523
third-party/vendor/swc_common/src/rustc_data_structures/stable_hasher.rs
vendored
Normal file
523
third-party/vendor/swc_common/src/rustc_data_structures/stable_hasher.rs
vendored
Normal file
|
|
@ -0,0 +1,523 @@
|
|||
use std::{
|
||||
hash::{BuildHasher, Hash, Hasher},
|
||||
mem,
|
||||
};
|
||||
|
||||
use siphasher::sip128::{Hash128, Hasher128, SipHasher24};
|
||||
|
||||
/// When hashing something that ends up affecting properties like symbol names,
|
||||
/// we want these symbol names to be calculated independently of other factors
|
||||
/// like what architecture you're compiling *from*.
|
||||
///
|
||||
/// To that end we always convert integers to little-endian format before
|
||||
/// hashing and the architecture dependent `isize` and `usize` types are
|
||||
/// extended to 64 bits if needed.
|
||||
pub struct StableHasher {
|
||||
state: SipHasher24,
|
||||
}
|
||||
|
||||
impl ::std::fmt::Debug for StableHasher {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||
write!(f, "{:?}", self.state)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StableHasherResult: Sized {
|
||||
fn finish(hasher: StableHasher) -> Self;
|
||||
}
|
||||
|
||||
impl StableHasher {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
StableHasher {
|
||||
state: SipHasher24::new_with_keys(0, 0),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn finish<W: StableHasherResult>(self) -> W {
|
||||
W::finish(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl StableHasherResult for u128 {
|
||||
#[inline]
|
||||
fn finish(hasher: StableHasher) -> Self {
|
||||
hasher.finalize().as_u128()
|
||||
}
|
||||
}
|
||||
|
||||
impl StableHasherResult for u64 {
|
||||
#[inline]
|
||||
fn finish(hasher: StableHasher) -> Self {
|
||||
hasher.finalize().h1
|
||||
}
|
||||
}
|
||||
|
||||
impl StableHasher {
|
||||
#[inline]
|
||||
pub fn finalize(self) -> Hash128 {
|
||||
self.state.finish128()
|
||||
}
|
||||
}
|
||||
|
||||
impl Hasher for StableHasher {
|
||||
fn finish(&self) -> u64 {
|
||||
panic!("use StableHasher::finalize instead");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write(&mut self, bytes: &[u8]) {
|
||||
self.state.write(bytes);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u8(&mut self, i: u8) {
|
||||
self.state.write_u8(i);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u16(&mut self, i: u16) {
|
||||
self.state.write_u16(i.to_le());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u32(&mut self, i: u32) {
|
||||
self.state.write_u32(i.to_le());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u64(&mut self, i: u64) {
|
||||
self.state.write_u64(i.to_le());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_u128(&mut self, i: u128) {
|
||||
self.state.write_u128(i.to_le());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_usize(&mut self, i: usize) {
|
||||
// Always treat usize as u64 so we get the same results on 32 and 64 bit
|
||||
// platforms. This is important for symbol hashes when cross compiling,
|
||||
// for example.
|
||||
self.state.write_u64((i as u64).to_le());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_i8(&mut self, i: i8) {
|
||||
self.state.write_i8(i);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_i16(&mut self, i: i16) {
|
||||
self.state.write_i16(i.to_le());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_i32(&mut self, i: i32) {
|
||||
self.state.write_i32(i.to_le());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_i64(&mut self, i: i64) {
|
||||
self.state.write_i64(i.to_le());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_i128(&mut self, i: i128) {
|
||||
self.state.write_i128(i.to_le());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_isize(&mut self, i: isize) {
|
||||
// Always treat isize as a 64-bit number so we get the same results on 32 and 64
|
||||
// bit platforms. This is important for symbol hashes when cross
|
||||
// compiling, for example. Sign extending here is preferable as it means
|
||||
// that the same negative number hashes the same on both 32 and 64 bit
|
||||
// platforms.
|
||||
let value = i as u64;
|
||||
|
||||
// Cold path
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
fn hash_value(state: &mut SipHasher24, value: u64) {
|
||||
state.write_u8(0xff);
|
||||
state.write_u64(value.to_le());
|
||||
}
|
||||
|
||||
// `isize` values often seem to have a small (positive) numeric value in
|
||||
// practice. To exploit this, if the value is small, we will hash a
|
||||
// smaller amount of bytes. However, we cannot just skip the leading
|
||||
// zero bytes, as that would produce the same hash e.g. if you hash two
|
||||
// values that have the same bit pattern when they are swapped. See https://github.com/rust-lang/rust/pull/93014 for context.
|
||||
//
|
||||
// Therefore, we employ the following strategy:
|
||||
// 1) When we encounter a value that fits within a single byte (the most common
|
||||
// case), we hash just that byte. This is the most common case that is
|
||||
// being optimized. However, we do not do this for the value 0xFF, as
|
||||
// that is a reserved prefix (a bit like in UTF-8). 2) When we encounter
|
||||
// a larger value, we hash a "marker" 0xFF and then the corresponding
|
||||
// 8 bytes. Since this prefix cannot occur when we hash a single byte, when we
|
||||
// hash two `isize`s that fit within a different amount of bytes, they
|
||||
// should always produce a different byte stream for the hasher.
|
||||
if value < 0xff {
|
||||
self.state.write_u8(value as u8);
|
||||
} else {
|
||||
hash_value(&mut self.state, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Something that implements `HashStable<CTX>` can be hashed in a way that is
|
||||
/// stable across multiple compilation sessions.
|
||||
pub trait HashStable<CTX> {
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher);
|
||||
}
|
||||
|
||||
/// Implement this for types that can be turned into stable keys like, for
|
||||
/// example, for DefId that can be converted to a DefPathHash. This is used for
|
||||
/// bringing maps into a predictable order before hashing them.
|
||||
pub trait ToStableHashKey<HCX> {
|
||||
type KeyType: Ord + Clone + Sized + HashStable<HCX>;
|
||||
fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType;
|
||||
}
|
||||
|
||||
// Implement HashStable by just calling `Hash::hash()`. This works fine for
|
||||
// self-contained values that don't depend on the hashing context `CTX`.
|
||||
#[macro_export]
|
||||
macro_rules! impl_stable_hash_via_hash {
|
||||
($t:ty) => {
|
||||
impl<CTX> $crate::rustc_data_structures::stable_hasher::HashStable<CTX> for $t {
|
||||
#[inline]
|
||||
fn hash_stable(
|
||||
&self,
|
||||
_: &mut CTX,
|
||||
hasher: &mut $crate::rustc_data_structures::stable_hasher::StableHasher,
|
||||
) {
|
||||
::std::hash::Hash::hash(self, hasher);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_stable_hash_via_hash!(i8);
|
||||
impl_stable_hash_via_hash!(i16);
|
||||
impl_stable_hash_via_hash!(i32);
|
||||
impl_stable_hash_via_hash!(i64);
|
||||
impl_stable_hash_via_hash!(isize);
|
||||
|
||||
impl_stable_hash_via_hash!(u8);
|
||||
impl_stable_hash_via_hash!(u16);
|
||||
impl_stable_hash_via_hash!(u32);
|
||||
impl_stable_hash_via_hash!(u64);
|
||||
impl_stable_hash_via_hash!(usize);
|
||||
|
||||
impl_stable_hash_via_hash!(u128);
|
||||
impl_stable_hash_via_hash!(i128);
|
||||
|
||||
impl_stable_hash_via_hash!(char);
|
||||
impl_stable_hash_via_hash!(());
|
||||
|
||||
impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.get().hash_stable(ctx, hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for f32 {
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
let val: u32 = unsafe { ::std::mem::transmute(*self) };
|
||||
val.hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for f64 {
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
let val: u64 = unsafe { ::std::mem::transmute(*self) };
|
||||
val.hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for ::std::cmp::Ordering {
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
(*self as i8).hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1: HashStable<CTX>, CTX> HashStable<CTX> for (T1,) {
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
let (ref _0,) = *self;
|
||||
_0.hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1: HashStable<CTX>, T2: HashStable<CTX>, CTX> HashStable<CTX> for (T1, T2) {
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
let (ref _0, ref _1) = *self;
|
||||
_0.hash_stable(ctx, hasher);
|
||||
_1.hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1, T2, T3, CTX> HashStable<CTX> for (T1, T2, T3)
|
||||
where
|
||||
T1: HashStable<CTX>,
|
||||
T2: HashStable<CTX>,
|
||||
T3: HashStable<CTX>,
|
||||
{
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
let (ref _0, ref _1, ref _2) = *self;
|
||||
_0.hash_stable(ctx, hasher);
|
||||
_1.hash_stable(ctx, hasher);
|
||||
_2.hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1, T2, T3, T4, CTX> HashStable<CTX> for (T1, T2, T3, T4)
|
||||
where
|
||||
T1: HashStable<CTX>,
|
||||
T2: HashStable<CTX>,
|
||||
T3: HashStable<CTX>,
|
||||
T4: HashStable<CTX>,
|
||||
{
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
let (ref _0, ref _1, ref _2, ref _3) = *self;
|
||||
_0.hash_stable(ctx, hasher);
|
||||
_1.hash_stable(ctx, hasher);
|
||||
_2.hash_stable(ctx, hasher);
|
||||
_3.hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.len().hash_stable(ctx, hasher);
|
||||
for item in self {
|
||||
item.hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
|
||||
#[inline]
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
(&self[..]).hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + HashStable<CTX>, CTX> HashStable<CTX> for Box<T> {
|
||||
#[inline]
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
(**self).hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + HashStable<CTX>, CTX> HashStable<CTX> for ::std::rc::Rc<T> {
|
||||
#[inline]
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
(**self).hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + HashStable<CTX>, CTX> HashStable<CTX> for ::std::sync::Arc<T> {
|
||||
#[inline]
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
(**self).hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for str {
|
||||
#[inline]
|
||||
fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.len().hash(hasher);
|
||||
self.as_bytes().hash(hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for String {
|
||||
#[inline]
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
(&self[..]).hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<HCX> ToStableHashKey<HCX> for String {
|
||||
type KeyType = String;
|
||||
|
||||
#[inline]
|
||||
fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for bool {
|
||||
#[inline]
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
(if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, CTX> HashStable<CTX> for Option<T>
|
||||
where
|
||||
T: HashStable<CTX>,
|
||||
{
|
||||
#[inline]
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
if let Some(ref value) = *self {
|
||||
1u8.hash_stable(ctx, hasher);
|
||||
value.hash_stable(ctx, hasher);
|
||||
} else {
|
||||
0u8.hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T1, T2, CTX> HashStable<CTX> for Result<T1, T2>
|
||||
where
|
||||
T1: HashStable<CTX>,
|
||||
T2: HashStable<CTX>,
|
||||
{
|
||||
#[inline]
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
mem::discriminant(self).hash_stable(ctx, hasher);
|
||||
match *self {
|
||||
Ok(ref x) => x.hash_stable(ctx, hasher),
|
||||
Err(ref x) => x.hash_stable(ctx, hasher),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, CTX> HashStable<CTX> for &'a T
|
||||
where
|
||||
T: HashStable<CTX> + ?Sized,
|
||||
{
|
||||
#[inline]
|
||||
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
|
||||
(**self).hash_stable(ctx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, CTX> HashStable<CTX> for ::std::mem::Discriminant<T> {
|
||||
#[inline]
|
||||
fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) {
|
||||
::std::hash::Hash::hash(self, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
// impl<I: ::indexed_vec::Idx, T, CTX> HashStable<CTX> for
|
||||
// ::indexed_vec::IndexVec<I, T> where
|
||||
// T: HashStable<CTX>,
|
||||
// {
|
||||
// fn hash_stable<W: StableHasherResult>(&self, ctx: &mut CTX, hasher: &mut
|
||||
// StableHasher<W>) { self.len().hash_stable(ctx, hasher);
|
||||
// for v in &self.raw {
|
||||
// v.hash_stable(ctx, hasher);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<I: ::indexed_vec::Idx, CTX> HashStable<CTX> for ::bit_set::BitSet<I> {
|
||||
// fn hash_stable<W: StableHasherResult>(&self, ctx: &mut CTX, hasher: &mut
|
||||
// StableHasher<W>) { self.words().hash_stable(ctx, hasher);
|
||||
// }
|
||||
// }
|
||||
|
||||
impl_stable_hash_via_hash!(::std::path::Path);
|
||||
impl_stable_hash_via_hash!(::std::path::PathBuf);
|
||||
|
||||
impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R>
|
||||
where
|
||||
K: ToStableHashKey<HCX> + Eq,
|
||||
V: HashStable<HCX>,
|
||||
R: BuildHasher,
|
||||
{
|
||||
#[inline]
|
||||
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
|
||||
stable_hash_reduce(
|
||||
hcx,
|
||||
hasher,
|
||||
self.iter(),
|
||||
self.len(),
|
||||
|hasher, hcx, (key, value)| {
|
||||
let key = key.to_stable_hash_key(hcx);
|
||||
key.hash_stable(hcx, hasher);
|
||||
value.hash_stable(hcx, hasher);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, R, HCX> HashStable<HCX> for ::std::collections::HashSet<K, R>
|
||||
where
|
||||
K: ToStableHashKey<HCX> + Eq,
|
||||
R: BuildHasher,
|
||||
{
|
||||
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
|
||||
stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| {
|
||||
let key = key.to_stable_hash_key(hcx);
|
||||
key.hash_stable(hcx, hasher);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V, HCX> HashStable<HCX> for ::std::collections::BTreeMap<K, V>
|
||||
where
|
||||
K: ToStableHashKey<HCX>,
|
||||
V: HashStable<HCX>,
|
||||
{
|
||||
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
|
||||
stable_hash_reduce(
|
||||
hcx,
|
||||
hasher,
|
||||
self.iter(),
|
||||
self.len(),
|
||||
|hasher, hcx, (key, value)| {
|
||||
let key = key.to_stable_hash_key(hcx);
|
||||
key.hash_stable(hcx, hasher);
|
||||
value.hash_stable(hcx, hasher);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, HCX> HashStable<HCX> for ::std::collections::BTreeSet<K>
|
||||
where
|
||||
K: ToStableHashKey<HCX>,
|
||||
{
|
||||
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
|
||||
stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| {
|
||||
let key = key.to_stable_hash_key(hcx);
|
||||
key.hash_stable(hcx, hasher);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn stable_hash_reduce<HCX, I, C, F>(
|
||||
hcx: &mut HCX,
|
||||
hasher: &mut StableHasher,
|
||||
mut collection: C,
|
||||
length: usize,
|
||||
hash_function: F,
|
||||
) where
|
||||
C: Iterator<Item = I>,
|
||||
F: Fn(&mut StableHasher, &mut HCX, I),
|
||||
{
|
||||
length.hash_stable(hcx, hasher);
|
||||
|
||||
match length {
|
||||
1 => {
|
||||
hash_function(hasher, hcx, collection.next().unwrap());
|
||||
}
|
||||
_ => {
|
||||
let hash = collection
|
||||
.map(|value| {
|
||||
let mut hasher = StableHasher::new();
|
||||
hash_function(&mut hasher, hcx, value);
|
||||
hasher.finish::<u128>()
|
||||
})
|
||||
.reduce(|accum, value| accum.wrapping_add(value));
|
||||
hash.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
third-party/vendor/swc_common/src/serializer.rs
vendored
Normal file
18
third-party/vendor/swc_common/src/serializer.rs
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#![allow(deprecated)]
|
||||
#![deprecated = "Not used by swc, and this will be removed with next breaking change"]
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[deprecated = "Not used by swc, and this will be removed with next breaking change"]
|
||||
pub struct Node<T> {
|
||||
#[serde(default, rename = "type")]
|
||||
pub ty: String,
|
||||
#[serde(flatten)]
|
||||
pub node: T,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Type {
|
||||
#[serde(rename = "type")]
|
||||
pub ty: String,
|
||||
}
|
||||
1805
third-party/vendor/swc_common/src/source_map.rs
vendored
Normal file
1805
third-party/vendor/swc_common/src/source_map.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
329
third-party/vendor/swc_common/src/sync.rs
vendored
Normal file
329
third-party/vendor/swc_common/src/sync.rs
vendored
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! This module defines types which are thread safe if `cfg!(feature =
|
||||
//! "concurrent")` is true.
|
||||
//!
|
||||
//! `Lrc` is an alias of either Rc or Arc.
|
||||
//!
|
||||
//! `Lock` is a mutex.
|
||||
//! It internally uses `parking_lot::Mutex` if cfg!(parallel_queries) is true,
|
||||
//! `RefCell` otherwise.
|
||||
//!
|
||||
//! `RwLock` is a read-write lock.
|
||||
//! It internally uses `parking_lot::RwLock` if cfg!(parallel_queries) is true,
|
||||
//! `RefCell` otherwise.
|
||||
//!
|
||||
//! `LockCell` is a thread safe version of `Cell`, with `set` and `get`
|
||||
//! operations. It can never deadlock. It uses `Cell` when
|
||||
//! cfg!(parallel_queries) is false, otherwise it is a `Lock`.
|
||||
//!
|
||||
//! `MTLock` is a mutex which disappears if cfg!(parallel_queries) is false.
|
||||
//!
|
||||
//! `MTRef` is a immutable reference if cfg!(parallel_queries), and an mutable
|
||||
//! reference otherwise.
|
||||
//!
|
||||
//! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send +
|
||||
//! Sync depending on the value of cfg!(parallel_queries).
|
||||
|
||||
#[cfg(not(feature = "concurrent"))]
|
||||
use std::cell::{RefCell as InnerRwLock, RefCell as InnerLock};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::HashMap,
|
||||
fmt,
|
||||
fmt::{Debug, Formatter},
|
||||
hash::{BuildHasher, Hash},
|
||||
};
|
||||
|
||||
#[cfg(feature = "concurrent")]
|
||||
use parking_lot::{Mutex as InnerLock, RwLock as InnerRwLock};
|
||||
|
||||
#[cfg(feature = "concurrent")]
|
||||
pub use self::concurrent::*;
|
||||
#[cfg(not(feature = "concurrent"))]
|
||||
pub use self::single::*;
|
||||
|
||||
#[cfg(feature = "concurrent")]
|
||||
mod concurrent {
|
||||
pub use std::{
|
||||
marker::{Send, Sync},
|
||||
sync::Arc as Lrc,
|
||||
};
|
||||
|
||||
pub use once_cell::sync::{Lazy, OnceCell};
|
||||
pub use parking_lot::{
|
||||
MappedMutexGuard as MappedLockGuard, MappedRwLockReadGuard as MappedReadGuard,
|
||||
MappedRwLockWriteGuard as MappedWriteGuard, MutexGuard as LockGuard,
|
||||
RwLockReadGuard as ReadGuard, RwLockWriteGuard as WriteGuard,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "concurrent"))]
|
||||
mod single {
|
||||
pub use once_cell::unsync::{Lazy, OnceCell};
|
||||
/// Dummy trait because swc_common is in single thread mode.
|
||||
pub trait Send {}
|
||||
/// Dummy trait because swc_common is in single thread mode.
|
||||
pub trait Sync {}
|
||||
|
||||
impl<T> Send for T where T: ?Sized {}
|
||||
impl<T> Sync for T where T: ?Sized {}
|
||||
|
||||
pub use std::{
|
||||
cell::{
|
||||
Ref as ReadGuard, RefMut as WriteGuard, RefMut as MappedWriteGuard,
|
||||
RefMut as LockGuard, RefMut as MappedLockGuard,
|
||||
},
|
||||
rc::{Rc as Lrc, Weak},
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Lock<T>(InnerLock<T>);
|
||||
|
||||
impl<T> Lock<T> {
|
||||
#[inline(always)]
|
||||
pub fn new(inner: T) -> Self {
|
||||
Lock(InnerLock::new(inner))
|
||||
}
|
||||
|
||||
// #[inline(always)]
|
||||
// pub fn into_inner(self) -> T {
|
||||
// self.0.into_inner()
|
||||
// }
|
||||
//
|
||||
// #[inline(always)]
|
||||
// pub fn get_mut(&mut self) -> &mut T {
|
||||
// self.0.get_mut()
|
||||
// }
|
||||
|
||||
// #[cfg(feature = "concurrent")]
|
||||
// #[inline(always)]
|
||||
// pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
|
||||
// self.0.try_lock()
|
||||
// }
|
||||
//
|
||||
// #[cfg(not(feature = "concurrent"))]
|
||||
// #[inline(always)]
|
||||
// pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
|
||||
// self.0.try_borrow_mut().ok()
|
||||
// }
|
||||
|
||||
#[cfg(feature = "concurrent")]
|
||||
#[inline(always)]
|
||||
pub fn lock(&self) -> LockGuard<'_, T> {
|
||||
self.0.lock()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "concurrent"))]
|
||||
#[inline(always)]
|
||||
pub fn lock(&self) -> LockGuard<'_, T> {
|
||||
self.0.borrow_mut()
|
||||
}
|
||||
|
||||
// #[inline(always)]
|
||||
// pub fn with_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
|
||||
// f(&mut *self.lock())
|
||||
// }
|
||||
|
||||
#[inline(always)]
|
||||
pub fn borrow(&self) -> LockGuard<'_, T> {
|
||||
self.lock()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn borrow_mut(&self) -> LockGuard<'_, T> {
|
||||
self.lock()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Default for Lock<T> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Lock::new(T::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> LockCell<T> {
|
||||
#[inline(always)]
|
||||
pub fn new(inner: T) -> Self {
|
||||
LockCell(Lock::new(inner))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set(&self, new_inner: T) {
|
||||
*self.0.lock() = new_inner;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get(&self) -> T
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
*self.0.lock()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HashMapExt<K, V> {
|
||||
/// Same as HashMap::insert, but it may panic if there's already an
|
||||
/// entry for `key` with a value not equal to `value`
|
||||
fn insert_same(&mut self, key: K, value: V);
|
||||
}
|
||||
|
||||
impl<K: Eq + Hash, V: Eq, S: BuildHasher> HashMapExt<K, V> for HashMap<K, V, S> {
|
||||
fn insert_same(&mut self, key: K, value: V) {
|
||||
self.entry(key)
|
||||
.and_modify(|old| assert!(*old == value))
|
||||
.or_insert(value);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + Debug> Debug for LockCell<T> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("LockCell")
|
||||
.field("value", &self.get())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Default for LockCell<T> {
|
||||
/// Creates a `LockCell<T>`, with the `Default` value for T.
|
||||
#[inline]
|
||||
fn default() -> LockCell<T> {
|
||||
LockCell::new(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Copy> PartialEq for LockCell<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &LockCell<T>) -> bool {
|
||||
self.get() == other.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq + Copy> Eq for LockCell<T> {}
|
||||
|
||||
impl<T: PartialOrd + Copy> PartialOrd for LockCell<T> {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &LockCell<T>) -> Option<Ordering> {
|
||||
self.get().partial_cmp(&other.get())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn lt(&self, other: &LockCell<T>) -> bool {
|
||||
self.get() < other.get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn le(&self, other: &LockCell<T>) -> bool {
|
||||
self.get() <= other.get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn gt(&self, other: &LockCell<T>) -> bool {
|
||||
self.get() > other.get()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn ge(&self, other: &LockCell<T>) -> bool {
|
||||
self.get() >= other.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Ord + Copy> Ord for LockCell<T> {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &LockCell<T>) -> Ordering {
|
||||
self.get().cmp(&other.get())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RwLock<T>(InnerRwLock<T>);
|
||||
|
||||
impl<T> RwLock<T> {
|
||||
#[inline(always)]
|
||||
pub fn new(inner: T) -> Self {
|
||||
RwLock(InnerRwLock::new(inner))
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "concurrent"))]
|
||||
#[inline(always)]
|
||||
pub fn read(&self) -> ReadGuard<'_, T> {
|
||||
self.0.borrow()
|
||||
}
|
||||
|
||||
#[cfg(feature = "concurrent")]
|
||||
#[inline(always)]
|
||||
pub fn read(&self) -> ReadGuard<'_, T> {
|
||||
self.0.read()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn borrow(&self) -> ReadGuard<'_, T> {
|
||||
self.read()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
self.0.get_mut()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn with_read_lock<F: FnOnce(&T) -> R, R>(&self, f: F) -> R {
|
||||
f(&*self.read())
|
||||
}
|
||||
|
||||
#[allow(clippy::result_unit_err)]
|
||||
#[cfg(not(feature = "concurrent"))]
|
||||
#[inline(always)]
|
||||
pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> {
|
||||
self.0.try_borrow_mut().map_err(|_| ())
|
||||
}
|
||||
|
||||
#[allow(clippy::result_unit_err)]
|
||||
#[cfg(feature = "concurrent")]
|
||||
#[inline(always)]
|
||||
pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> {
|
||||
self.0.try_write().ok_or(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "concurrent"))]
|
||||
#[inline(always)]
|
||||
pub fn write(&self) -> WriteGuard<'_, T> {
|
||||
self.0.borrow_mut()
|
||||
}
|
||||
|
||||
#[cfg(feature = "concurrent")]
|
||||
#[inline(always)]
|
||||
pub fn write(&self) -> WriteGuard<'_, T> {
|
||||
self.0.write()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn with_write_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
|
||||
f(&mut *self.write())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
|
||||
self.write()
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Probably a bad idea
|
||||
impl<T: Clone> Clone for RwLock<T> {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
RwLock::new(self.borrow().clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LockCell<T>(Lock<T>);
|
||||
1451
third-party/vendor/swc_common/src/syntax_pos.rs
vendored
Normal file
1451
third-party/vendor/swc_common/src/syntax_pos.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
311
third-party/vendor/swc_common/src/syntax_pos/analyze_source_file.rs
vendored
Normal file
311
third-party/vendor/swc_common/src/syntax_pos/analyze_source_file.rs
vendored
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Finds all newlines, multi-byte characters, and non-narrow characters in a
|
||||
/// SourceFile.
|
||||
///
|
||||
/// This function will use an SSE2 enhanced implementation if hardware support
|
||||
/// is detected at runtime.
|
||||
pub fn analyze_source_file(
|
||||
src: &str,
|
||||
source_file_start_pos: BytePos,
|
||||
) -> (Vec<BytePos>, Vec<MultiByteChar>, Vec<NonNarrowChar>) {
|
||||
let mut lines = vec![source_file_start_pos];
|
||||
let mut multi_byte_chars = vec![];
|
||||
let mut non_narrow_chars = vec![];
|
||||
|
||||
// Calls the right implementation, depending on hardware support available.
|
||||
analyze_source_file_generic(
|
||||
src,
|
||||
src.len(),
|
||||
source_file_start_pos,
|
||||
&mut lines,
|
||||
&mut multi_byte_chars,
|
||||
&mut non_narrow_chars,
|
||||
);
|
||||
|
||||
// The code above optimistically registers a new line *after* each \n
|
||||
// it encounters. If that point is already outside the source_file, remove
|
||||
// it again.
|
||||
if let Some(&last_line_start) = lines.last() {
|
||||
let source_file_end = source_file_start_pos + BytePos::from_usize(src.len());
|
||||
assert!(source_file_end >= last_line_start);
|
||||
if last_line_start == source_file_end {
|
||||
lines.pop();
|
||||
}
|
||||
}
|
||||
|
||||
(lines, multi_byte_chars, non_narrow_chars)
|
||||
}
|
||||
|
||||
// `scan_len` determines the number of bytes in `src` to scan. Note that the
|
||||
// function can read past `scan_len` if a multi-byte character start within the
|
||||
// range but extends past it. The overflow is returned by the function.
|
||||
fn analyze_source_file_generic(
|
||||
src: &str,
|
||||
scan_len: usize,
|
||||
output_offset: BytePos,
|
||||
lines: &mut Vec<BytePos>,
|
||||
multi_byte_chars: &mut Vec<MultiByteChar>,
|
||||
non_narrow_chars: &mut Vec<NonNarrowChar>,
|
||||
) -> usize {
|
||||
assert!(src.len() >= scan_len);
|
||||
let mut i = 0;
|
||||
let src_bytes = src.as_bytes();
|
||||
|
||||
while i < scan_len {
|
||||
let byte = unsafe {
|
||||
// We verified that i < scan_len <= src.len()
|
||||
*src_bytes.get_unchecked(i)
|
||||
};
|
||||
|
||||
// How much to advance in order to get to the next UTF-8 char in the
|
||||
// string.
|
||||
let mut char_len = 1;
|
||||
|
||||
if byte < 32 {
|
||||
// This is an ASCII control character, it could be one of the cases
|
||||
// that are interesting to us.
|
||||
|
||||
let pos = BytePos::from_usize(i) + output_offset;
|
||||
|
||||
match byte {
|
||||
b'\r' => {
|
||||
if let Some(b'\n') = src_bytes.get(i + 1) {
|
||||
lines.push(pos + BytePos(2));
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
lines.push(pos + BytePos(1));
|
||||
}
|
||||
|
||||
b'\n' => {
|
||||
lines.push(pos + BytePos(1));
|
||||
}
|
||||
b'\t' => {
|
||||
non_narrow_chars.push(NonNarrowChar::Tab(pos));
|
||||
}
|
||||
_ => {
|
||||
non_narrow_chars.push(NonNarrowChar::ZeroWidth(pos));
|
||||
}
|
||||
}
|
||||
} else if byte >= 127 {
|
||||
// The slow path:
|
||||
// This is either ASCII control character "DEL" or the beginning of
|
||||
// a multibyte char. Just decode to `char`.
|
||||
let c = src[i..].chars().next().unwrap();
|
||||
char_len = c.len_utf8();
|
||||
|
||||
let pos = BytePos::from_usize(i) + output_offset;
|
||||
|
||||
if char_len > 1 {
|
||||
assert!((2..=4).contains(&char_len));
|
||||
let mbc = MultiByteChar {
|
||||
pos,
|
||||
bytes: char_len as u8,
|
||||
};
|
||||
multi_byte_chars.push(mbc);
|
||||
}
|
||||
|
||||
// Assume control characters are zero width.
|
||||
// FIXME: How can we decide between `width` and `width_cjk`?
|
||||
let char_width = UnicodeWidthChar::width(c).unwrap_or(0);
|
||||
|
||||
if char_width != 1 {
|
||||
non_narrow_chars.push(NonNarrowChar::new(pos, char_width));
|
||||
}
|
||||
}
|
||||
|
||||
i += char_len;
|
||||
}
|
||||
|
||||
i - scan_len
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::identity_op)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
macro_rules! test {
|
||||
(case: $test_name:ident,
|
||||
text: $text:expr,
|
||||
source_file_start_pos: $source_file_start_pos:expr,
|
||||
lines: $lines:expr,
|
||||
multi_byte_chars: $multi_byte_chars:expr,
|
||||
non_narrow_chars: $non_narrow_chars:expr,) => {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
let (lines, multi_byte_chars, non_narrow_chars) =
|
||||
analyze_source_file($text, BytePos($source_file_start_pos));
|
||||
|
||||
let expected_lines: Vec<BytePos> =
|
||||
$lines.into_iter().map(|pos| BytePos(pos)).collect();
|
||||
|
||||
assert_eq!(lines, expected_lines);
|
||||
|
||||
let expected_mbcs: Vec<MultiByteChar> = $multi_byte_chars
|
||||
.into_iter()
|
||||
.map(|(pos, bytes)| MultiByteChar {
|
||||
pos: BytePos(pos),
|
||||
bytes,
|
||||
})
|
||||
.collect();
|
||||
|
||||
assert_eq!(multi_byte_chars, expected_mbcs);
|
||||
|
||||
let expected_nncs: Vec<NonNarrowChar> = $non_narrow_chars
|
||||
.into_iter()
|
||||
.map(|(pos, width)| NonNarrowChar::new(BytePos(pos), width))
|
||||
.collect();
|
||||
|
||||
assert_eq!(non_narrow_chars, expected_nncs);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test!(
|
||||
case: empty_text,
|
||||
text: "",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![],
|
||||
multi_byte_chars: vec![],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: newlines_short,
|
||||
text: "a\nc",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0, 2],
|
||||
multi_byte_chars: vec![],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: newlines_long,
|
||||
text: "012345678\nabcdef012345678\na",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0, 10, 26],
|
||||
multi_byte_chars: vec![],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: newline_and_multi_byte_char_in_same_chunk,
|
||||
text: "01234β789\nbcdef0123456789abcdef",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0, 11],
|
||||
multi_byte_chars: vec![(5, 2)],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: newline_and_control_char_in_same_chunk,
|
||||
text: "01234\u{07}6789\nbcdef0123456789abcdef",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0, 11],
|
||||
multi_byte_chars: vec![],
|
||||
non_narrow_chars: vec![(5, 0)],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: multi_byte_char_short,
|
||||
text: "aβc",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0],
|
||||
multi_byte_chars: vec![(1, 2)],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: multi_byte_char_long,
|
||||
text: "0123456789abcΔf012345β",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0],
|
||||
multi_byte_chars: vec![(13, 2), (22, 2)],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: multi_byte_char_across_chunk_boundary,
|
||||
text: "0123456789abcdeΔ123456789abcdef01234",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0],
|
||||
multi_byte_chars: vec![(15, 2)],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: multi_byte_char_across_chunk_boundary_tail,
|
||||
text: "0123456789abcdeΔ....",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0],
|
||||
multi_byte_chars: vec![(15, 2)],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: non_narrow_short,
|
||||
text: "0\t2",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0],
|
||||
multi_byte_chars: vec![],
|
||||
non_narrow_chars: vec![(1, 4)],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: non_narrow_long,
|
||||
text: "01\t3456789abcdef01234567\u{07}9",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0],
|
||||
multi_byte_chars: vec![],
|
||||
non_narrow_chars: vec![(2, 4), (24, 0)],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: output_offset_all,
|
||||
text: "01\t345\n789abcΔf01234567\u{07}9\nbcΔf",
|
||||
source_file_start_pos: 1000,
|
||||
lines: vec![0 + 1000, 7 + 1000, 27 + 1000],
|
||||
multi_byte_chars: vec![(13 + 1000, 2), (29 + 1000, 2)],
|
||||
non_narrow_chars: vec![(2 + 1000, 4), (24 + 1000, 0)],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: unix_lf,
|
||||
text: "/**\n * foo\n */\n012345678\nabcdef012345678\na",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0, 4, 11, 15, 25, 41],
|
||||
multi_byte_chars: vec![],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: windows_cr,
|
||||
text: "/**\r * foo\r */\r012345678\rabcdef012345678\ra",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0, 4, 11, 15, 25, 41],
|
||||
multi_byte_chars: vec![],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
|
||||
test!(
|
||||
case: windows_crlf,
|
||||
text: "/**\r\n * foo\r\n */\r\n012345678\r\nabcdef012345678\r\na",
|
||||
source_file_start_pos: 0,
|
||||
lines: vec![0, 5, 13, 18, 29, 46],
|
||||
multi_byte_chars: vec![],
|
||||
non_narrow_chars: vec![],
|
||||
);
|
||||
}
|
||||
606
third-party/vendor/swc_common/src/syntax_pos/hygiene.rs
vendored
Normal file
606
third-party/vendor/swc_common/src/syntax_pos/hygiene.rs
vendored
Normal file
|
|
@ -0,0 +1,606 @@
|
|||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Machinery for hygienic macros, inspired by the `MTWT[1]` paper.
|
||||
//!
|
||||
//! `[1]` Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler.
|
||||
//! 2012. *Macros that work together: Compile-time bindings, partial expansion,
|
||||
//! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
|
||||
//! DOI=10.1017/S0956796812000093 <https://doi.org/10.1017/S0956796812000093>
|
||||
|
||||
#[allow(unused)]
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::GLOBALS;
|
||||
use crate::collections::AHashMap;
|
||||
|
||||
/// A SyntaxContext represents a chain of macro expansions (represented by
|
||||
/// marks).
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct SyntaxContext(#[cfg_attr(feature = "__rkyv", omit_bounds)] u32);
|
||||
|
||||
#[cfg(feature = "arbitrary")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
|
||||
impl<'a> arbitrary::Arbitrary<'a> for SyntaxContext {
|
||||
fn arbitrary(_: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
|
||||
Ok(SyntaxContext::empty())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct SyntaxContextData {
|
||||
outer_mark: Mark,
|
||||
prev_ctxt: SyntaxContext,
|
||||
// This context, but with all transparent and semi-transparent marks filtered away.
|
||||
opaque: SyntaxContext,
|
||||
// This context, but with all transparent marks filtered away.
|
||||
opaque_and_semitransparent: SyntaxContext,
|
||||
}
|
||||
|
||||
/// A mark is a unique id associated with a macro expansion.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Mark(u32);
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct MarkData {
|
||||
pub(crate) parent: Mark,
|
||||
pub(crate) is_builtin: bool,
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct MutableMarkContext(pub u32, pub u32, pub u32);
|
||||
|
||||
// List of proxy calls injected by the host in the plugin's runtime context.
|
||||
// When related calls being executed inside of the plugin, it'll call these
|
||||
// proxies instead which'll call actual host fn.
|
||||
extern "C" {
|
||||
// Instead of trying to copy-serialize `Mark`, this fn directly consume
|
||||
// inner raw value as well as fn and let each context constructs struct
|
||||
// on their side.
|
||||
fn __mark_fresh_proxy(mark: u32) -> u32;
|
||||
fn __mark_parent_proxy(self_mark: u32) -> u32;
|
||||
fn __mark_is_builtin_proxy(self_mark: u32) -> u32;
|
||||
fn __mark_set_builtin_proxy(self_mark: u32, is_builtin: u32);
|
||||
fn __syntax_context_apply_mark_proxy(self_syntax_context: u32, mark: u32) -> u32;
|
||||
fn __syntax_context_outer_proxy(self_mark: u32) -> u32;
|
||||
|
||||
// These are proxy fn uses serializable context to pass forward mutated param
|
||||
// with return value back to the guest.
|
||||
fn __mark_is_descendant_of_proxy(self_mark: u32, ancestor: u32, allocated_ptr: i32);
|
||||
fn __mark_least_ancestor(a: u32, b: u32, allocated_ptr: i32);
|
||||
fn __syntax_context_remove_mark_proxy(self_mark: u32, allocated_ptr: i32);
|
||||
}
|
||||
|
||||
impl Mark {
|
||||
/// Shortcut for `Mark::fresh(Mark::root())`
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new() -> Self {
|
||||
Mark::fresh(Mark::root())
|
||||
}
|
||||
|
||||
pub fn fresh(parent: Mark) -> Self {
|
||||
// Note: msvc tries to link against proxied fn for normal build,
|
||||
// have to limit build target to wasm only to avoid it.
|
||||
#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
|
||||
return Mark(unsafe { __mark_fresh_proxy(parent.as_u32()) });
|
||||
|
||||
// https://github.com/swc-project/swc/pull/3492#discussion_r802224857
|
||||
// We loosen conditions here for the cases like running plugin's test without
|
||||
// targeting wasm32-*.
|
||||
#[cfg(not(all(feature = "__plugin_mode", target_arch = "wasm32")))]
|
||||
return with_marks(|marks| {
|
||||
marks.push(MarkData {
|
||||
parent,
|
||||
is_builtin: false,
|
||||
});
|
||||
Mark(marks.len() as u32 - 1)
|
||||
});
|
||||
}
|
||||
|
||||
/// The mark of the theoretical expansion that generates freshly parsed,
|
||||
/// unexpanded AST.
|
||||
#[inline]
|
||||
pub const fn root() -> Self {
|
||||
Mark(0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_u32(raw: u32) -> Mark {
|
||||
Mark(raw)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn parent(self) -> Mark {
|
||||
#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
|
||||
return Mark(unsafe { __mark_parent_proxy(self.0) });
|
||||
|
||||
#[cfg(not(all(feature = "__plugin_mode", target_arch = "wasm32")))]
|
||||
return with_marks(|marks| marks[self.0 as usize].parent);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_builtin(self) -> bool {
|
||||
#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
|
||||
return unsafe { __mark_is_builtin_proxy(self.0) != 0 };
|
||||
|
||||
#[cfg(not(all(feature = "__plugin_mode", target_arch = "wasm32")))]
|
||||
{
|
||||
assert_ne!(self, Mark::root());
|
||||
|
||||
with_marks(|marks| marks[self.0 as usize].is_builtin)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_is_builtin(self, is_builtin: bool) {
|
||||
#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
|
||||
unsafe {
|
||||
__mark_set_builtin_proxy(self.0, is_builtin as u32)
|
||||
}
|
||||
#[cfg(not(all(feature = "__plugin_mode", target_arch = "wasm32")))]
|
||||
{
|
||||
assert_ne!(self, Mark::root());
|
||||
|
||||
with_marks(|marks| marks[self.0 as usize].is_builtin = is_builtin)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_assignments)]
|
||||
#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
|
||||
pub fn is_descendant_of(mut self, ancestor: Mark) -> bool {
|
||||
// This code path executed inside of the guest memory context.
|
||||
// In here, preallocate memory for the context.
|
||||
|
||||
use crate::plugin::serialized::VersionedSerializable;
|
||||
let serialized = crate::plugin::serialized::PluginSerializedBytes::try_serialize(
|
||||
&VersionedSerializable::new(MutableMarkContext(0, 0, 0)),
|
||||
)
|
||||
.expect("Should be serializable");
|
||||
let (ptr, len) = serialized.as_ptr();
|
||||
|
||||
// Calling host proxy fn. Inside of host proxy, host will
|
||||
// write the result into allocated context in the guest memory space.
|
||||
unsafe {
|
||||
__mark_is_descendant_of_proxy(self.0, ancestor.0, ptr as _);
|
||||
}
|
||||
|
||||
// Deserialize result, assign / return values as needed.
|
||||
let context: MutableMarkContext =
|
||||
crate::plugin::serialized::PluginSerializedBytes::from_raw_ptr(
|
||||
ptr,
|
||||
len.try_into().expect("Should able to convert ptr length"),
|
||||
)
|
||||
.deserialize()
|
||||
.expect("Should able to deserialize")
|
||||
.into_inner();
|
||||
|
||||
self = Mark::from_u32(context.0);
|
||||
|
||||
return context.2 != 0;
|
||||
}
|
||||
|
||||
#[cfg(not(all(feature = "__plugin_mode", target_arch = "wasm32")))]
|
||||
pub fn is_descendant_of(mut self, ancestor: Mark) -> bool {
|
||||
with_marks(|marks| {
|
||||
while self != ancestor {
|
||||
if self == Mark::root() {
|
||||
return false;
|
||||
}
|
||||
self = marks[self.0 as usize].parent;
|
||||
}
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(unused_mut, unused_assignments)]
|
||||
#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
|
||||
pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark {
|
||||
use crate::plugin::serialized::VersionedSerializable;
|
||||
|
||||
let serialized = crate::plugin::serialized::PluginSerializedBytes::try_serialize(
|
||||
&VersionedSerializable::new(MutableMarkContext(0, 0, 0)),
|
||||
)
|
||||
.expect("Should be serializable");
|
||||
let (ptr, len) = serialized.as_ptr();
|
||||
|
||||
unsafe {
|
||||
__mark_least_ancestor(a.0, b.0, ptr as _);
|
||||
}
|
||||
|
||||
let context: MutableMarkContext =
|
||||
crate::plugin::serialized::PluginSerializedBytes::from_raw_ptr(
|
||||
ptr,
|
||||
len.try_into().expect("Should able to convert ptr length"),
|
||||
)
|
||||
.deserialize()
|
||||
.expect("Should able to deserialize")
|
||||
.into_inner();
|
||||
a = Mark::from_u32(context.0);
|
||||
b = Mark::from_u32(context.1);
|
||||
|
||||
return Mark(context.2);
|
||||
}
|
||||
|
||||
/// Computes a mark such that both input marks are descendants of (or equal
|
||||
/// to) the returned mark. That is, the following holds:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// let la = least_ancestor(a, b);
|
||||
/// assert!(a.is_descendant_of(la))
|
||||
/// assert!(b.is_descendant_of(la))
|
||||
/// ```
|
||||
#[allow(unused_mut)]
|
||||
#[cfg(not(all(feature = "__plugin_mode", target_arch = "wasm32")))]
|
||||
pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark {
|
||||
with_marks(|marks| {
|
||||
// Compute the path from a to the root
|
||||
let mut a_path = HashSet::<Mark>::default();
|
||||
while a != Mark::root() {
|
||||
a_path.insert(a);
|
||||
a = marks[a.0 as usize].parent;
|
||||
}
|
||||
|
||||
// While the path from b to the root hasn't intersected, move up the tree
|
||||
while !a_path.contains(&b) {
|
||||
b = marks[b.0 as usize].parent;
|
||||
}
|
||||
|
||||
b
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct HygieneData {
|
||||
syntax_contexts: Vec<SyntaxContextData>,
|
||||
markings: AHashMap<(SyntaxContext, Mark), SyntaxContext>,
|
||||
}
|
||||
|
||||
impl Default for HygieneData {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl HygieneData {
|
||||
pub(crate) fn new() -> Self {
|
||||
HygieneData {
|
||||
syntax_contexts: vec![SyntaxContextData {
|
||||
outer_mark: Mark::root(),
|
||||
prev_ctxt: SyntaxContext(0),
|
||||
opaque: SyntaxContext(0),
|
||||
opaque_and_semitransparent: SyntaxContext(0),
|
||||
}],
|
||||
markings: HashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
|
||||
GLOBALS.with(|globals| {
|
||||
#[cfg(feature = "parking_lot")]
|
||||
return f(&mut globals.hygiene_data.lock());
|
||||
|
||||
#[cfg(not(feature = "parking_lot"))]
|
||||
return f(&mut *globals.hygiene_data.lock().unwrap());
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn with_marks<T, F: FnOnce(&mut Vec<MarkData>) -> T>(f: F) -> T {
|
||||
GLOBALS.with(|globals| {
|
||||
#[cfg(feature = "parking_lot")]
|
||||
return f(&mut globals.marks.lock());
|
||||
|
||||
#[cfg(not(feature = "parking_lot"))]
|
||||
return f(&mut *globals.marks.lock().unwrap());
|
||||
})
|
||||
}
|
||||
|
||||
// pub fn clear_markings() {
|
||||
// HygieneData::with(|data| data.markings = HashMap::default());
|
||||
// }
|
||||
|
||||
impl SyntaxContext {
|
||||
pub const fn empty() -> Self {
|
||||
SyntaxContext(0)
|
||||
}
|
||||
|
||||
/// Returns `true` if `self` is marked with `mark`.
|
||||
///
|
||||
/// Panics if `mark` is not a valid mark.
|
||||
pub fn has_mark(self, mark: Mark) -> bool {
|
||||
debug_assert_ne!(
|
||||
mark,
|
||||
Mark::root(),
|
||||
"Cannot check if a span contains a `ROOT` mark"
|
||||
);
|
||||
|
||||
let mut ctxt = self;
|
||||
|
||||
loop {
|
||||
if ctxt == SyntaxContext::empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let m = ctxt.remove_mark();
|
||||
if m == mark {
|
||||
return true;
|
||||
}
|
||||
if m == Mark::root() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_u32(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_u32(raw: u32) -> SyntaxContext {
|
||||
SyntaxContext(raw)
|
||||
}
|
||||
|
||||
/// Extend a syntax context with a given mark and default transparency for
|
||||
/// that mark.
|
||||
pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
|
||||
#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
|
||||
return unsafe { SyntaxContext(__syntax_context_apply_mark_proxy(self.0, mark.0)) };
|
||||
|
||||
#[cfg(not(all(feature = "__plugin_mode", target_arch = "wasm32")))]
|
||||
{
|
||||
assert_ne!(mark, Mark::root());
|
||||
self.apply_mark_internal(mark)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn apply_mark_internal(self, mark: Mark) -> SyntaxContext {
|
||||
HygieneData::with(|data| {
|
||||
let syntax_contexts = &mut data.syntax_contexts;
|
||||
let mut opaque = syntax_contexts[self.0 as usize].opaque;
|
||||
let opaque_and_semitransparent =
|
||||
syntax_contexts[self.0 as usize].opaque_and_semitransparent;
|
||||
|
||||
let prev_ctxt = opaque;
|
||||
opaque = *data.markings.entry((prev_ctxt, mark)).or_insert_with(|| {
|
||||
let new_opaque = SyntaxContext(syntax_contexts.len() as u32);
|
||||
syntax_contexts.push(SyntaxContextData {
|
||||
outer_mark: mark,
|
||||
prev_ctxt,
|
||||
opaque: new_opaque,
|
||||
opaque_and_semitransparent: new_opaque,
|
||||
});
|
||||
new_opaque
|
||||
});
|
||||
|
||||
let prev_ctxt = self;
|
||||
*data.markings.entry((prev_ctxt, mark)).or_insert_with(|| {
|
||||
let new_opaque_and_semitransparent_and_transparent =
|
||||
SyntaxContext(syntax_contexts.len() as u32);
|
||||
syntax_contexts.push(SyntaxContextData {
|
||||
outer_mark: mark,
|
||||
prev_ctxt,
|
||||
opaque,
|
||||
opaque_and_semitransparent,
|
||||
});
|
||||
new_opaque_and_semitransparent_and_transparent
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
|
||||
pub fn remove_mark(&mut self) -> Mark {
|
||||
use crate::plugin::serialized::VersionedSerializable;
|
||||
|
||||
let context = VersionedSerializable::new(MutableMarkContext(0, 0, 0));
|
||||
let serialized = crate::plugin::serialized::PluginSerializedBytes::try_serialize(&context)
|
||||
.expect("Should be serializable");
|
||||
let (ptr, len) = serialized.as_ptr();
|
||||
|
||||
unsafe {
|
||||
__syntax_context_remove_mark_proxy(self.0, ptr as _);
|
||||
}
|
||||
|
||||
let context: MutableMarkContext =
|
||||
crate::plugin::serialized::PluginSerializedBytes::from_raw_ptr(
|
||||
ptr,
|
||||
len.try_into().expect("Should able to convert ptr length"),
|
||||
)
|
||||
.deserialize()
|
||||
.expect("Should able to deserialize")
|
||||
.into_inner();
|
||||
|
||||
*self = SyntaxContext(context.0);
|
||||
|
||||
return Mark::from_u32(context.2);
|
||||
}
|
||||
|
||||
/// Pulls a single mark off of the syntax context. This effectively moves
|
||||
/// the context up one macro definition level. That is, if we have a
|
||||
/// nested macro definition as follows:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// macro_rules! f {
|
||||
/// macro_rules! g {
|
||||
/// ...
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// and we have a SyntaxContext that is referring to something declared by
|
||||
/// an invocation of g (call it g1), calling remove_mark will result in
|
||||
/// the SyntaxContext for the invocation of f that created g1.
|
||||
/// Returns the mark that was removed.
|
||||
#[cfg(not(all(feature = "__plugin_mode", target_arch = "wasm32")))]
|
||||
pub fn remove_mark(&mut self) -> Mark {
|
||||
HygieneData::with(|data| {
|
||||
let outer_mark = data.syntax_contexts[self.0 as usize].outer_mark;
|
||||
*self = data.syntax_contexts[self.0 as usize].prev_ctxt;
|
||||
outer_mark
|
||||
})
|
||||
}
|
||||
|
||||
/// Adjust this context for resolution in a scope created by the given
|
||||
/// expansion. For example, consider the following three resolutions of
|
||||
/// `f`:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// mod foo {
|
||||
/// pub fn f() {}
|
||||
/// } // `f`'s `SyntaxContext` is empty.
|
||||
/// m!(f);
|
||||
/// macro m($f:ident) {
|
||||
/// mod bar {
|
||||
/// pub fn f() {} // `f`'s `SyntaxContext` has a single `Mark` from `m`.
|
||||
/// pub fn $f() {} // `$f`'s `SyntaxContext` is empty.
|
||||
/// }
|
||||
/// foo::f(); // `f`'s `SyntaxContext` has a single `Mark` from `m`
|
||||
/// //^ Since `mod foo` is outside this expansion, `adjust` removes the mark from `f`,
|
||||
/// //| and it resolves to `::foo::f`.
|
||||
/// bar::f(); // `f`'s `SyntaxContext` has a single `Mark` from `m`
|
||||
/// //^ Since `mod bar` not outside this expansion, `adjust` does not change `f`,
|
||||
/// //| and it resolves to `::bar::f`.
|
||||
/// bar::$f(); // `f`'s `SyntaxContext` is empty.
|
||||
/// //^ Since `mod bar` is not outside this expansion, `adjust` does not change `$f`,
|
||||
/// //| and it resolves to `::bar::$f`.
|
||||
/// }
|
||||
/// ```
|
||||
/// This returns the expansion whose definition scope we use to privacy
|
||||
/// check the resolution, or `None` if we privacy check as usual (i.e.
|
||||
/// not w.r.t. a macro definition scope).
|
||||
pub fn adjust(&mut self, expansion: Mark) -> Option<Mark> {
|
||||
let mut scope = None;
|
||||
while !expansion.is_descendant_of(self.outer()) {
|
||||
scope = Some(self.remove_mark());
|
||||
}
|
||||
scope
|
||||
}
|
||||
|
||||
/// Adjust this context for resolution in a scope created by the given
|
||||
/// expansion via a glob import with the given `SyntaxContext`.
|
||||
/// For example:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// m!(f);
|
||||
/// macro m($i:ident) {
|
||||
/// mod foo {
|
||||
/// pub fn f() {} // `f`'s `SyntaxContext` has a single `Mark` from `m`.
|
||||
/// pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
|
||||
/// }
|
||||
/// n(f);
|
||||
/// macro n($j:ident) {
|
||||
/// use foo::*;
|
||||
/// f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
|
||||
/// //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::f`.
|
||||
/// $i(); // `$i`'s `SyntaxContext` has a mark from `n`
|
||||
/// //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::$i`.
|
||||
/// $j(); // `$j`'s `SyntaxContext` has a mark from `m`
|
||||
/// //^ This cannot be glob-adjusted, so this is a resolution error.
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// This returns `None` if the context cannot be glob-adjusted.
|
||||
/// Otherwise, it returns the scope to use when privacy checking (see
|
||||
/// `adjust` for details).
|
||||
pub fn glob_adjust(
|
||||
&mut self,
|
||||
expansion: Mark,
|
||||
mut glob_ctxt: SyntaxContext,
|
||||
) -> Option<Option<Mark>> {
|
||||
let mut scope = None;
|
||||
while !expansion.is_descendant_of(glob_ctxt.outer()) {
|
||||
scope = Some(glob_ctxt.remove_mark());
|
||||
if self.remove_mark() != scope.unwrap() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
if self.adjust(expansion).is_some() {
|
||||
return None;
|
||||
}
|
||||
Some(scope)
|
||||
}
|
||||
|
||||
/// Undo `glob_adjust` if possible:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// if let Some(privacy_checking_scope) = self.reverse_glob_adjust(expansion, glob_ctxt) {
|
||||
/// assert!(self.glob_adjust(expansion, glob_ctxt) == Some(privacy_checking_scope));
|
||||
/// }
|
||||
/// ```
|
||||
pub fn reverse_glob_adjust(
|
||||
&mut self,
|
||||
expansion: Mark,
|
||||
mut glob_ctxt: SyntaxContext,
|
||||
) -> Option<Option<Mark>> {
|
||||
if self.adjust(expansion).is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut marks = Vec::new();
|
||||
while !expansion.is_descendant_of(glob_ctxt.outer()) {
|
||||
marks.push(glob_ctxt.remove_mark());
|
||||
}
|
||||
|
||||
let scope = marks.last().cloned();
|
||||
while let Some(mark) = marks.pop() {
|
||||
*self = self.apply_mark(mark);
|
||||
}
|
||||
Some(scope)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn outer(self) -> Mark {
|
||||
#[cfg(all(feature = "__plugin_mode", target_arch = "wasm32"))]
|
||||
return unsafe { Mark(__syntax_context_outer_proxy(self.0)) };
|
||||
|
||||
#[cfg(not(all(feature = "__plugin_mode", target_arch = "wasm32")))]
|
||||
HygieneData::with(|data| data.syntax_contexts[self.0 as usize].outer_mark)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SyntaxContext {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "#{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Mark {
|
||||
fn default() -> Self {
|
||||
Mark::root()
|
||||
}
|
||||
}
|
||||
49
third-party/vendor/swc_common/src/util/iter.rs
vendored
Normal file
49
third-party/vendor/swc_common/src/util/iter.rs
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
pub trait IteratorExt: Iterator {
|
||||
/// Copied from https://stackoverflow.com/a/49456265/6193633
|
||||
fn chain_with<F, I>(self, f: F) -> ChainWith<Self, F, I::IntoIter>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnOnce() -> I,
|
||||
I: IntoIterator<Item = Self::Item>,
|
||||
{
|
||||
ChainWith {
|
||||
base: self,
|
||||
factory: Some(f),
|
||||
iterator: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Iterator> IteratorExt for I {}
|
||||
|
||||
pub struct ChainWith<B, F, I> {
|
||||
base: B,
|
||||
factory: Option<F>,
|
||||
iterator: Option<I>,
|
||||
}
|
||||
|
||||
impl<B, F, I> Iterator for ChainWith<B, F, I::IntoIter>
|
||||
where
|
||||
B: Iterator,
|
||||
F: FnOnce() -> I,
|
||||
I: IntoIterator<Item = B::Item>,
|
||||
{
|
||||
type Item = I::Item;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(b) = self.base.next() {
|
||||
return Some(b);
|
||||
}
|
||||
|
||||
// Exhausted the first, generate the second
|
||||
|
||||
if let Some(f) = self.factory.take() {
|
||||
self.iterator = Some(f().into_iter());
|
||||
}
|
||||
|
||||
self.iterator
|
||||
.as_mut()
|
||||
.expect("There must be an iterator")
|
||||
.next()
|
||||
}
|
||||
}
|
||||
2
third-party/vendor/swc_common/src/util/map.rs
vendored
Normal file
2
third-party/vendor/swc_common/src/util/map.rs
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/// Moved
|
||||
pub use swc_visit::util::map::Map;
|
||||
4
third-party/vendor/swc_common/src/util/mod.rs
vendored
Normal file
4
third-party/vendor/swc_common/src/util/mod.rs
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
pub mod iter;
|
||||
pub mod map;
|
||||
pub mod move_map;
|
||||
pub mod take;
|
||||
1
third-party/vendor/swc_common/src/util/move_map.rs
vendored
Normal file
1
third-party/vendor/swc_common/src/util/move_map.rs
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub use swc_visit::util::move_map::MoveMap;
|
||||
56
third-party/vendor/swc_common/src/util/take.rs
vendored
Normal file
56
third-party/vendor/swc_common/src/util/take.rs
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
use std::mem::replace;
|
||||
|
||||
use crate::{Span, DUMMY_SP};
|
||||
|
||||
/// Helper for people who are working on `VisitMut`.
|
||||
///
|
||||
///
|
||||
/// This trait is implemented for ast nodes. If not and you need it, please file
|
||||
/// an issue.
|
||||
pub trait Take: Sized {
|
||||
fn take(&mut self) -> Self {
|
||||
replace(self, Self::dummy())
|
||||
}
|
||||
|
||||
/// Create a dummy value of this type.
|
||||
fn dummy() -> Self;
|
||||
|
||||
/// Mutate `self` using `op`, which accepts owned data.
|
||||
#[inline]
|
||||
fn map_with_mut<F>(&mut self, op: F)
|
||||
where
|
||||
F: FnOnce(Self) -> Self,
|
||||
{
|
||||
let dummy = Self::dummy();
|
||||
let cur_val = replace(self, dummy);
|
||||
let new_val = op(cur_val);
|
||||
let _dummy = replace(self, new_val);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Take for Option<T> {
|
||||
fn dummy() -> Self {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Take for Box<T>
|
||||
where
|
||||
T: Take,
|
||||
{
|
||||
fn dummy() -> Self {
|
||||
Box::new(T::dummy())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Take for Vec<T> {
|
||||
fn dummy() -> Self {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl Take for Span {
|
||||
fn dummy() -> Self {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
24
third-party/vendor/swc_common/tests/ast_serde.rs
vendored
Normal file
24
third-party/vendor/swc_common/tests/ast_serde.rs
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
use serde_json::from_str;
|
||||
use swc_common::ast_serde;
|
||||
|
||||
#[ast_serde]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Ambiguous {
|
||||
#[tag("A")]
|
||||
A(A),
|
||||
#[tag("B")]
|
||||
B(B),
|
||||
}
|
||||
#[ast_serde("B")]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct A {}
|
||||
|
||||
#[ast_serde("B")]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct B {}
|
||||
|
||||
#[test]
|
||||
fn deserialize() {
|
||||
assert_eq!(A {}, from_str(r#"{"type": "A"}"#).unwrap());
|
||||
assert_eq!(B {}, from_str(r#"{"type": "B"}"#).unwrap());
|
||||
}
|
||||
38
third-party/vendor/swc_common/tests/attr_interop.rs
vendored
Normal file
38
third-party/vendor/swc_common/tests/attr_interop.rs
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
//! Test that `#[span]` and `#[fold]` can be used at same time.
|
||||
use serde::{self, Deserialize, Serialize};
|
||||
use swc_common::{self, ast_node, Span, Spanned};
|
||||
|
||||
#[ast_node("Class")]
|
||||
// See https://github.com/rust-lang/rust/issues/44925
|
||||
pub struct Class {
|
||||
#[span]
|
||||
pub has_span: HasSpan,
|
||||
pub s: String,
|
||||
}
|
||||
|
||||
#[ast_node("Tuple")]
|
||||
pub struct Tuple(#[span] HasSpan, usize, usize);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Spanned, Serialize, Deserialize)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "rkyv-impl"),
|
||||
archive(bound(serialize = "__S: rkyv::ser::Serializer + rkyv::ser::ScratchSpace"))
|
||||
)]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive(check_bytes))]
|
||||
#[cfg_attr(feature = "rkyv-impl", archive_attr(repr(C)))]
|
||||
pub struct HasSpan {
|
||||
#[cfg_attr(feature = "__rkyv", omit_bounds)]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[ast_node]
|
||||
pub enum Node {
|
||||
#[tag("Class")]
|
||||
Class(Class),
|
||||
#[tag("Tuple")]
|
||||
Tuple(Tuple),
|
||||
}
|
||||
1
third-party/vendor/swc_common/tests/concurrent.js
vendored
Normal file
1
third-party/vendor/swc_common/tests/concurrent.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
const foo = 1;
|
||||
41
third-party/vendor/swc_common/tests/concurrent.rs
vendored
Normal file
41
third-party/vendor/swc_common/tests/concurrent.rs
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#![cfg(feature = "concurrent")]
|
||||
|
||||
use std::{env, path::PathBuf, sync::Arc};
|
||||
|
||||
use rayon::prelude::*;
|
||||
use swc_common::{sync::Lrc, FilePathMapping, SourceFile, SourceMap};
|
||||
|
||||
#[test]
|
||||
fn no_overlap() {
|
||||
let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
|
||||
|
||||
let files: Vec<Lrc<SourceFile>> = (0..100000)
|
||||
.into_par_iter()
|
||||
.map(|_| {
|
||||
cm.load_file(
|
||||
&PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
|
||||
.join("tests")
|
||||
.join("concurrent.js"),
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// This actually tests if there is overlap
|
||||
|
||||
let mut start = files.clone();
|
||||
start.sort_by_key(|f| f.start_pos);
|
||||
let mut end = files;
|
||||
end.sort_by_key(|f| f.end_pos);
|
||||
|
||||
start
|
||||
.into_par_iter()
|
||||
.zip(end)
|
||||
.for_each(|(start, end): (Arc<SourceFile>, Arc<SourceFile>)| {
|
||||
assert_eq!(start.start_pos, end.start_pos);
|
||||
assert_eq!(start.end_pos, end.end_pos);
|
||||
assert!(start.start_pos < start.end_pos);
|
||||
|
||||
cm.lookup_char_pos(start.start_pos);
|
||||
});
|
||||
}
|
||||
6
third-party/vendor/swc_common/tests/empty.rs
vendored
Normal file
6
third-party/vendor/swc_common/tests/empty.rs
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
use swc_common::*;
|
||||
|
||||
pub struct Struct {}
|
||||
|
||||
#[derive(FromVariant)]
|
||||
pub enum Enum {}
|
||||
9
third-party/vendor/swc_common/tests/issue_3159.rs
vendored
Normal file
9
third-party/vendor/swc_common/tests/issue_3159.rs
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
use swc_common::ast_serde;
|
||||
|
||||
#[ast_serde]
|
||||
pub enum Message {
|
||||
#[tag("Request")]
|
||||
Request(String),
|
||||
#[tag("Response")]
|
||||
Response(u8),
|
||||
}
|
||||
38
third-party/vendor/swc_common/tests/source_map.rs
vendored
Normal file
38
third-party/vendor/swc_common/tests/source_map.rs
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#![cfg(feature = "concurrent")]
|
||||
|
||||
use rayon::{prelude::*, ThreadPoolBuilder};
|
||||
use swc_common::{FileName, FilePathMapping, SourceMap};
|
||||
|
||||
#[test]
|
||||
fn stress() {
|
||||
let _ = ThreadPoolBuilder::new().num_threads(100).build_global();
|
||||
let fm = SourceMap::new(FilePathMapping::empty());
|
||||
|
||||
(0..10000).into_par_iter().for_each(|_| {
|
||||
fm.new_source_file(
|
||||
FileName::Anon,
|
||||
"@Entity()
|
||||
export class Product extends TimestampedEntity {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
public id!: string;
|
||||
|
||||
@Column()
|
||||
public price!: number;
|
||||
|
||||
@Column({ enum: ProductType })
|
||||
public type!: ProductType;
|
||||
|
||||
@Column()
|
||||
public productEntityId!: string;
|
||||
|
||||
/* ANCHOR: Relations ------------------------------------------------------ */
|
||||
@OneToMany(() => Order, (order) => order.product)
|
||||
public orders!: Order[];
|
||||
|
||||
@OneToMany(() => Discount, (discount) => discount.product)
|
||||
public discounts!: Discount[];
|
||||
}"
|
||||
.into(),
|
||||
);
|
||||
})
|
||||
}
|
||||
19
third-party/vendor/swc_common/tests/spanned_attr.rs
vendored
Normal file
19
third-party/vendor/swc_common/tests/spanned_attr.rs
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use swc_common::{BytePos, Span, Spanned};
|
||||
|
||||
#[test]
|
||||
fn lo_hi() {
|
||||
#[derive(Spanned)]
|
||||
struct LoHi {
|
||||
#[span(lo)]
|
||||
pub lo: BytePos,
|
||||
#[span(hi)]
|
||||
pub hi: BytePos,
|
||||
}
|
||||
|
||||
let lo = BytePos(0);
|
||||
let hi = BytePos(5);
|
||||
assert_eq!(
|
||||
LoHi { lo, hi }.span(),
|
||||
Span::new(lo, hi, Default::default())
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue