Add some size assertions

This commit is contained in:
Lukas Wirth 2024-01-26 10:43:25 +01:00
parent d8ef6c24cc
commit 5a343415e8
13 changed files with 194 additions and 198 deletions

View File

@ -25,13 +25,13 @@ extern crate ra_ap_rustc_abi as rustc_abi;
pub mod db;
pub mod attr;
pub mod path;
pub mod builtin_type;
pub mod per_ns;
pub mod item_scope;
pub mod path;
pub mod per_ns;
pub mod lower;
pub mod expander;
pub mod lower;
pub mod dyn_map;
@ -46,24 +46,24 @@ pub use self::hir::type_ref;
pub mod body;
pub mod resolver;
mod trace;
pub mod nameres;
mod trace;
pub mod src;
pub mod child_by_source;
pub mod src;
pub mod visibility;
pub mod find_path;
pub mod import_map;
pub mod visibility;
pub use rustc_abi as layout;
use triomphe::Arc;
#[cfg(test)]
mod test_db;
#[cfg(test)]
mod macro_expansion_tests;
mod pretty;
#[cfg(test)]
mod test_db;
use std::{
hash::{Hash, Hasher},
@ -73,7 +73,6 @@ use std::{
use base_db::{impl_intern_key, salsa, CrateId, Edition};
use hir_expand::{
ast_id_map::{AstIdNode, FileAstId},
attrs::{Attr, AttrId, AttrInput},
builtin_attr_macro::BuiltinAttrExpander,
builtin_derive_macro::BuiltinDeriveExpander,
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
@ -1274,60 +1273,6 @@ fn macro_call_as_call_id_with_eager(
Ok(res)
}
fn derive_macro_as_call_id(
db: &dyn DefDatabase,
item_attr: &AstIdWithPath<ast::Adt>,
derive_attr_index: AttrId,
derive_pos: u32,
call_site: Span,
krate: CrateId,
resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
let (macro_id, def_id) = resolver(item_attr.path.clone())
.filter(|(_, def_id)| def_id.is_derive())
.ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
let call_id = def_id.as_lazy_macro(
db.upcast(),
krate,
MacroCallKind::Derive {
ast_id: item_attr.ast_id,
derive_index: derive_pos,
derive_attr_index,
},
call_site,
);
Ok((macro_id, def_id, call_id))
}
fn attr_macro_as_call_id(
db: &dyn DefDatabase,
item_attr: &AstIdWithPath<ast::Item>,
macro_attr: &Attr,
krate: CrateId,
def: MacroDefId,
) -> MacroCallId {
let arg = match macro_attr.input.as_deref() {
Some(AttrInput::TokenTree(tt)) => {
let mut tt = tt.as_ref().clone();
tt.delimiter = tt::Delimiter::invisible_spanned(macro_attr.span);
Some(tt)
}
_ => None,
};
def.as_lazy_macro(
db.upcast(),
krate,
MacroCallKind::Attr {
ast_id: item_attr.ast_id,
attr_args: arg.map(Arc::new),
invoc_attr_index: macro_attr.id,
},
macro_attr.span,
)
}
#[derive(Debug)]
pub struct UnresolvedMacro {
pub path: hir_expand::mod_path::ModPath,

View File

@ -1,16 +1,21 @@
//! Post-nameres attribute resolution.
use hir_expand::{attrs::Attr, MacroCallId};
use base_db::CrateId;
use hir_expand::{
attrs::{Attr, AttrId, AttrInput},
MacroCallId, MacroCallKind, MacroDefId,
};
use span::Span;
use syntax::{ast, SmolStr};
use triomphe::Arc;
use crate::{
attr::builtin::{find_builtin_attr_idx, TOOL_MODULES},
attr_macro_as_call_id,
db::DefDatabase,
item_scope::BuiltinShadowMode,
nameres::path_resolution::ResolveMode,
path::{ModPath, PathKind},
AstIdWithPath, LocalModuleId, UnresolvedMacro,
path::{self, ModPath, PathKind},
AstIdWithPath, LocalModuleId, MacroId, UnresolvedMacro,
};
use super::{DefMap, MacroSubNs};
@ -93,3 +98,57 @@ impl DefMap {
false
}
}
pub(super) fn attr_macro_as_call_id(
db: &dyn DefDatabase,
item_attr: &AstIdWithPath<ast::Item>,
macro_attr: &Attr,
krate: CrateId,
def: MacroDefId,
) -> MacroCallId {
let arg = match macro_attr.input.as_deref() {
Some(AttrInput::TokenTree(tt)) => {
let mut tt = tt.as_ref().clone();
tt.delimiter = tt::Delimiter::invisible_spanned(macro_attr.span);
Some(tt)
}
_ => None,
};
def.as_lazy_macro(
db.upcast(),
krate,
MacroCallKind::Attr {
ast_id: item_attr.ast_id,
attr_args: arg.map(Arc::new),
invoc_attr_index: macro_attr.id,
},
macro_attr.span,
)
}
pub(super) fn derive_macro_as_call_id(
db: &dyn DefDatabase,
item_attr: &AstIdWithPath<ast::Adt>,
derive_attr_index: AttrId,
derive_pos: u32,
call_site: Span,
krate: CrateId,
resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>,
) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
let (macro_id, def_id) = resolver(item_attr.path.clone())
.filter(|(_, def_id)| def_id.is_derive())
.ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
let call_id = def_id.as_lazy_macro(
db.upcast(),
krate,
MacroCallKind::Derive {
ast_id: item_attr.ast_id,
derive_index: derive_pos,
derive_attr_index,
},
call_site,
);
Ok((macro_id, def_id, call_id))
}

View File

@ -30,9 +30,7 @@ use triomphe::Arc;
use crate::{
attr::Attrs,
attr_macro_as_call_id,
db::DefDatabase,
derive_macro_as_call_id,
item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
item_tree::{
self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
@ -40,6 +38,7 @@ use crate::{
},
macro_call_as_call_id, macro_call_as_call_id_with_eager,
nameres::{
attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id},
diagnostics::DefDiagnostic,
mod_resolution::ModDir,
path_resolution::ReachedFixedPoint,
@ -1245,7 +1244,9 @@ impl DefCollector<'_> {
MacroDefId { kind: MacroDefKind::BuiltInAttr(expander, _),.. }
if expander.is_derive()
) {
// Resolved to `#[derive]`
// Resolved to `#[derive]`, we don't actually expand this attribute like
// normal (as that would just be an identity expansion with extra output)
// Instead we treat derive attributes special and apply them separately.
let item_tree = tree.item_tree(self.db);
let ast_adt_id: FileAstId<ast::Adt> = match *mod_item {
@ -1284,7 +1285,8 @@ impl DefCollector<'_> {
}
// We treat the #[derive] macro as an attribute call, but we do not resolve it for nameres collection.
// This is just a trick to be able to resolve the input to derives as proper paths.
// This is just a trick to be able to resolve the input to derives
// as proper paths in `Semantics`.
// Check the comment in [`builtin_attr_macro`].
let call_id = attr_macro_as_call_id(
self.db,

View File

@ -4,6 +4,7 @@ use std::iter;
use hir_expand::{span_map::SpanMapRef, InFile};
use la_arena::ArenaMap;
use stdx::assert_eq_size;
use syntax::ast;
use triomphe::Arc;
@ -24,6 +25,7 @@ pub enum RawVisibility {
/// `pub`.
Public,
}
assert_eq_size!(RawVisibility, 48);
impl RawVisibility {
pub(crate) const fn private() -> RawVisibility {

View File

@ -48,11 +48,13 @@ impl BuiltinAttrExpander {
register_builtin! { expand:
(bench, Bench) => dummy_attr_expand,
(cfg, Cfg) => dummy_attr_expand,
(cfg_attr, CfgAttr) => dummy_attr_expand,
(cfg_accessible, CfgAccessible) => dummy_attr_expand,
(cfg_eval, CfgEval) => dummy_attr_expand,
(derive, Derive) => derive_attr_expand,
(derive, Derive) => derive_expand,
// derive const is equivalent to derive for our proposes.
(derive_const, DeriveConst) => derive_attr_expand,
(derive_const, DeriveConst) => derive_expand,
(global_allocator, GlobalAllocator) => dummy_attr_expand,
(test, Test) => dummy_attr_expand,
(test_case, TestCase) => dummy_attr_expand
@ -91,7 +93,7 @@ fn dummy_attr_expand(
/// always resolve as a derive without nameres recollecting them.
/// So this hacky approach is a lot more friendly for us, though it does require a bit of support in
/// [`hir::Semantics`] to make this work.
fn derive_attr_expand(
fn derive_expand(
db: &dyn ExpandDatabase,
id: MacroCallId,
tt: &tt::Subtree,

View File

@ -26,6 +26,7 @@ pub mod span_map;
mod fixup;
use attrs::collect_attrs;
use stdx::assert_eq_size;
use triomphe::Arc;
use std::{fmt, hash::Hash};
@ -175,6 +176,7 @@ pub struct MacroCallLoc {
pub kind: MacroCallKind,
pub call_site: Span,
}
assert_eq_size!(MacroCallLoc, 104);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId {
@ -185,6 +187,7 @@ pub struct MacroDefId {
pub allow_internal_unsafe: bool,
pub span: Span,
}
assert_eq_size!(MacroDefId, 44);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacroDefKind {

View File

@ -15,6 +15,7 @@ use crate::{
use base_db::CrateId;
use smallvec::SmallVec;
use span::SyntaxContextId;
use stdx::assert_eq_size;
use syntax::{ast, AstNode};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -22,6 +23,7 @@ pub struct ModPath {
pub kind: PathKind,
segments: SmallVec<[Name; 1]>,
}
assert_eq_size!(ModPath, 40);
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UnescapedModPath<'a>(&'a ModPath);

View File

@ -2,6 +2,7 @@
use std::fmt;
use stdx::assert_eq_size;
use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr};
/// `Name` is a wrapper around string, which is used in hir for both references
@ -13,6 +14,7 @@ use syntax::{ast, format_smolstr, utils::is_raw_identifier, SmolStr};
/// name without "r#".
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Name(Repr);
assert_eq_size!(Name, 24);
/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]

View File

@ -24,12 +24,12 @@
mod semantics;
mod source_analyzer;
mod from_id;
mod attrs;
mod from_id;
mod has_source;
pub mod diagnostics;
pub mod db;
pub mod diagnostics;
pub mod symbols;
mod display;
@ -70,13 +70,12 @@ use hir_ty::{
primitive::UintTy,
traits::FnTrait,
AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId,
WhereClause,
GenericArgData, InferenceDiagnostic, Interner, ParamKind, QuantifiedWhereClause, Scalar,
Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind,
ValueTyDefId, WhereClause,
};
use itertools::Itertools;
use nameres::diagnostics::DefDiagnosticKind;
use once_cell::unsync::Lazy;
use rustc_hash::FxHashSet;
use stdx::{impl_from, never};
use syntax::{
@ -1592,53 +1591,46 @@ impl DefWithBody {
}
for diag in source_map.diagnostics() {
match diag {
BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push(
InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into(),
),
BodyDiagnostic::MacroError { node, message } => acc.push(
MacroError {
node: (*node).map(|it| it.into()),
precise_location: None,
message: message.to_string(),
}
.into(),
),
BodyDiagnostic::UnresolvedProcMacro { node, krate } => acc.push(
UnresolvedProcMacro {
node: (*node).map(|it| it.into()),
precise_location: None,
macro_name: None,
kind: MacroKind::ProcMacro,
krate: *krate,
}
.into(),
),
BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push(
UnresolvedMacroCall {
macro_call: (*node).map(|ast_ptr| ast_ptr.into()),
precise_location: None,
path: path.clone(),
is_bang: true,
}
.into(),
),
acc.push(match diag {
BodyDiagnostic::InactiveCode { node, cfg, opts } => {
InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into()
}
BodyDiagnostic::MacroError { node, message } => MacroError {
node: (*node).map(|it| it.into()),
precise_location: None,
message: message.to_string(),
}
.into(),
BodyDiagnostic::UnresolvedProcMacro { node, krate } => UnresolvedProcMacro {
node: (*node).map(|it| it.into()),
precise_location: None,
macro_name: None,
kind: MacroKind::ProcMacro,
krate: *krate,
}
.into(),
BodyDiagnostic::UnresolvedMacroCall { node, path } => UnresolvedMacroCall {
macro_call: (*node).map(|ast_ptr| ast_ptr.into()),
precise_location: None,
path: path.clone(),
is_bang: true,
}
.into(),
BodyDiagnostic::UnreachableLabel { node, name } => {
acc.push(UnreachableLabel { node: *node, name: name.clone() }.into())
UnreachableLabel { node: *node, name: name.clone() }.into()
}
BodyDiagnostic::UndeclaredLabel { node, name } => {
acc.push(UndeclaredLabel { node: *node, name: name.clone() }.into())
UndeclaredLabel { node: *node, name: name.clone() }.into()
}
}
});
}
let infer = db.infer(self.into());
let source_map = Lazy::new(|| db.body_with_source_map(self.into()).1);
let expr_syntax = |expr| source_map.expr_syntax(expr).expect("unexpected synthetic");
let pat_syntax = |pat| source_map.pat_syntax(pat).expect("unexpected synthetic");
for d in &infer.diagnostics {
match d {
&hir_ty::InferenceDiagnostic::NoSuchField { field: expr, private } => {
acc.push(match d {
&InferenceDiagnostic::NoSuchField { field: expr, private } => {
let expr_or_pat = match expr {
ExprOrPatId::ExprId(expr) => {
source_map.field_syntax(expr).map(AstPtr::wrap_left)
@ -1647,57 +1639,48 @@ impl DefWithBody {
source_map.pat_field_syntax(pat).map(AstPtr::wrap_right)
}
};
acc.push(NoSuchField { field: expr_or_pat, private }.into())
NoSuchField { field: expr_or_pat, private }.into()
}
&hir_ty::InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
acc.push(
MismatchedArgCount { call_expr: expr_syntax(call_expr), expected, found }
.into(),
)
&InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
MismatchedArgCount { call_expr: expr_syntax(call_expr), expected, found }.into()
}
&hir_ty::InferenceDiagnostic::PrivateField { expr, field } => {
&InferenceDiagnostic::PrivateField { expr, field } => {
let expr = expr_syntax(expr);
let field = field.into();
acc.push(PrivateField { expr, field }.into())
PrivateField { expr, field }.into()
}
&hir_ty::InferenceDiagnostic::PrivateAssocItem { id, item } => {
&InferenceDiagnostic::PrivateAssocItem { id, item } => {
let expr_or_pat = match id {
ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left),
ExprOrPatId::PatId(pat) => pat_syntax(pat).map(AstPtr::wrap_right),
};
let item = item.into();
acc.push(PrivateAssocItem { expr_or_pat, item }.into())
PrivateAssocItem { expr_or_pat, item }.into()
}
hir_ty::InferenceDiagnostic::ExpectedFunction { call_expr, found } => {
InferenceDiagnostic::ExpectedFunction { call_expr, found } => {
let call_expr = expr_syntax(*call_expr);
acc.push(
ExpectedFunction {
call: call_expr,
found: Type::new(db, DefWithBodyId::from(self), found.clone()),
}
.into(),
)
ExpectedFunction {
call: call_expr,
found: Type::new(db, DefWithBodyId::from(self), found.clone()),
}
.into()
}
hir_ty::InferenceDiagnostic::UnresolvedField {
InferenceDiagnostic::UnresolvedField {
expr,
receiver,
name,
method_with_same_name_exists,
} => {
let expr = expr_syntax(*expr);
acc.push(
UnresolvedField {
expr,
name: name.clone(),
receiver: Type::new(db, DefWithBodyId::from(self), receiver.clone()),
method_with_same_name_exists: *method_with_same_name_exists,
}
.into(),
)
UnresolvedField {
expr,
name: name.clone(),
receiver: Type::new(db, DefWithBodyId::from(self), receiver.clone()),
method_with_same_name_exists: *method_with_same_name_exists,
}
.into()
}
hir_ty::InferenceDiagnostic::UnresolvedMethodCall {
InferenceDiagnostic::UnresolvedMethodCall {
expr,
receiver,
name,
@ -1705,50 +1688,38 @@ impl DefWithBody {
assoc_func_with_same_name,
} => {
let expr = expr_syntax(*expr);
acc.push(
UnresolvedMethodCall {
expr,
name: name.clone(),
receiver: Type::new(db, DefWithBodyId::from(self), receiver.clone()),
field_with_same_name: field_with_same_name
.clone()
.map(|ty| Type::new(db, DefWithBodyId::from(self), ty)),
assoc_func_with_same_name: *assoc_func_with_same_name,
}
.into(),
)
UnresolvedMethodCall {
expr,
name: name.clone(),
receiver: Type::new(db, DefWithBodyId::from(self), receiver.clone()),
field_with_same_name: field_with_same_name
.clone()
.map(|ty| Type::new(db, DefWithBodyId::from(self), ty)),
assoc_func_with_same_name: *assoc_func_with_same_name,
}
.into()
}
&hir_ty::InferenceDiagnostic::UnresolvedAssocItem { id } => {
&InferenceDiagnostic::UnresolvedAssocItem { id } => {
let expr_or_pat = match id {
ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left),
ExprOrPatId::PatId(pat) => pat_syntax(pat).map(AstPtr::wrap_right),
};
acc.push(UnresolvedAssocItem { expr_or_pat }.into())
UnresolvedAssocItem { expr_or_pat }.into()
}
&hir_ty::InferenceDiagnostic::BreakOutsideOfLoop {
expr,
is_break,
bad_value_break,
} => {
&InferenceDiagnostic::BreakOutsideOfLoop { expr, is_break, bad_value_break } => {
let expr = expr_syntax(expr);
acc.push(BreakOutsideOfLoop { expr, is_break, bad_value_break }.into())
BreakOutsideOfLoop { expr, is_break, bad_value_break }.into()
}
hir_ty::InferenceDiagnostic::TypedHole { expr, expected } => {
InferenceDiagnostic::TypedHole { expr, expected } => {
let expr = expr_syntax(*expr);
acc.push(
TypedHole {
expr,
expected: Type::new(db, DefWithBodyId::from(self), expected.clone()),
}
.into(),
)
TypedHole {
expr,
expected: Type::new(db, DefWithBodyId::from(self), expected.clone()),
}
.into()
}
&hir_ty::InferenceDiagnostic::MismatchedTupleStructPatArgCount {
pat,
expected,
found,
} => {
&InferenceDiagnostic::MismatchedTupleStructPatArgCount { pat, expected, found } => {
let expr_or_pat = match pat {
ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left),
ExprOrPatId::PatId(pat) => {
@ -1762,11 +1733,9 @@ impl DefWithBody {
InFile { file_id, value: ptr }
}
};
acc.push(
MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into(),
)
MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into()
}
}
});
}
for (pat_or_expr, mismatch) in infer.type_mismatches() {
let expr_or_pat = match pat_or_expr {
@ -1805,8 +1774,6 @@ impl DefWithBody {
}
}
let hir_body = db.body(self.into());
if let Ok(borrowck_results) = db.borrowck(self.into()) {
for borrowck_result in borrowck_results.iter() {
let mir_body = &borrowck_result.mir_body;
@ -1828,7 +1795,7 @@ impl DefWithBody {
)
}
let mol = &borrowck_result.mutability_of_locals;
for (binding_id, binding_data) in hir_body.bindings.iter() {
for (binding_id, binding_data) in body.bindings.iter() {
if binding_data.problems.is_some() {
// We should report specific diagnostics for these problems, not `need-mut` and `unused-mut`.
continue;

View File

@ -234,7 +234,7 @@ where
let mut stack = NonEmptyVec::new(entry);
while let Some((token, abs_range)) = conv.bump() {
let tt::Subtree { delimiter, token_trees: result } = stack.last_mut();
let tt::Subtree { delimiter, token_trees } = stack.last_mut();
let tt = match token.as_leaf() {
Some(leaf) => tt::TokenTree::Leaf(leaf.clone()),
@ -243,7 +243,7 @@ where
COMMENT => {
let span = conv.span_for(abs_range);
if let Some(tokens) = conv.convert_doc_comment(&token, span) {
result.extend(tokens);
token_trees.extend(tokens);
}
continue;
}
@ -317,7 +317,7 @@ where
span: conv
.span_for(TextRange::at(abs_range.start(), TextSize::of('\''))),
});
result.push(apostrophe.into());
token_trees.push(apostrophe.into());
let ident = tt::Leaf::from(tt::Ident {
text: SmolStr::new(&token.to_text(conv)[1..]),
@ -326,7 +326,7 @@ where
abs_range.end(),
)),
});
result.push(ident.into());
token_trees.push(ident.into());
continue;
}
_ => continue,
@ -337,7 +337,7 @@ where
},
};
result.push(tt);
token_trees.push(tt);
}
// If we get here, we've consumed all input tokens.

View File

@ -1,10 +1,8 @@
//! File and span related types.
// FIXME: This should be moved into its own crate to get rid of the dependency inversion, base-db
// has business depending on tt, tt should depend on a span crate only (which unforunately will have
// to depend on salsa)
use std::fmt::{self, Write};
use salsa::InternId;
use stdx::assert_eq_size;
mod map;
@ -38,6 +36,7 @@ pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(!0 - 1));
pub type Span = SpanData<SyntaxContextId>;
assert_eq_size!(Span, 20);
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct SpanData<Ctx> {

View File

@ -59,3 +59,12 @@ macro_rules! impl_from {
)*
}
}
#[macro_export]
macro_rules! assert_eq_size {
($($ty:ty,)+ $val:expr $(,)?) => {
const _: () = {
$(core::mem::transmute::<[u8; $val], $ty>;)+
};
};
}

View File

@ -6,7 +6,9 @@
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
["(", ")"],
["#[", "]"],
["#![", "]"]
],
"colorizedBracketPairs": [
["{", "}"],
@ -17,6 +19,8 @@
{ "open": "{", "close": "}" },
{ "open": "[", "close": "]" },
{ "open": "(", "close": ")" },
{ "open": "#[", "close": "]" },
{ "open": "#![", "close": "]" },
{ "open": "\"", "close": "\"", "notIn": ["string"] },
{ "open": "/*", "close": " */" },
{ "open": "`", "close": "`", "notIn": ["string"] }