Auto merge of #16237 - Veykril:expand-arc-alloc, r=Veykril

internal: Remove unnecessary `Arc` allocations in `macro_expand`
This commit is contained in:
bors 2024-01-03 14:40:10 +00:00
commit 9279c6566b
6 changed files with 40 additions and 19 deletions

View file

@ -390,7 +390,13 @@ fn parse_macro_expansion(
let expand_to = loc.expand_to(); let expand_to = loc.expand_to();
let mbe::ValueResult { value: tt, err } = macro_expand(db, macro_file.macro_call_id, loc); let mbe::ValueResult { value: tt, err } = macro_expand(db, macro_file.macro_call_id, loc);
let (parse, rev_token_map) = token_tree_to_syntax_node(&tt, expand_to); let (parse, rev_token_map) = token_tree_to_syntax_node(
match &tt {
CowArc::Arc(it) => it,
CowArc::Owned(it) => it,
},
expand_to,
);
ExpandResult { value: (parse, Arc::new(rev_token_map)), err } ExpandResult { value: (parse, Arc::new(rev_token_map)), err }
} }
@ -669,15 +675,20 @@ fn macro_expander(db: &dyn ExpandDatabase, id: MacroDefId) -> TokenExpander {
} }
} }
enum CowArc<T> {
Arc(Arc<T>),
Owned(T),
}
fn macro_expand( fn macro_expand(
db: &dyn ExpandDatabase, db: &dyn ExpandDatabase,
macro_call_id: MacroCallId, macro_call_id: MacroCallId,
loc: MacroCallLoc, loc: MacroCallLoc,
) -> ExpandResult<Arc<tt::Subtree>> { ) -> ExpandResult<CowArc<tt::Subtree>> {
let _p = profile::span("macro_expand"); let _p = profile::span("macro_expand");
let ExpandResult { value: tt, mut err } = match loc.def.kind { let ExpandResult { value: tt, mut err } = match loc.def.kind {
MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id), MacroDefKind::ProcMacro(..) => return db.expand_proc_macro(macro_call_id).map(CowArc::Arc),
MacroDefKind::BuiltInDerive(expander, ..) => { MacroDefKind::BuiltInDerive(expander, ..) => {
let (root, map) = parse_with_map(db, loc.kind.file_id()); let (root, map) = parse_with_map(db, loc.kind.file_id());
let root = root.syntax_node(); let root = root.syntax_node();
@ -692,7 +703,7 @@ fn macro_expand(
let ValueResult { value, err } = db.macro_arg(macro_call_id); let ValueResult { value, err } = db.macro_arg(macro_call_id);
let Some((macro_arg, undo_info)) = value else { let Some((macro_arg, undo_info)) = value else {
return ExpandResult { return ExpandResult {
value: Arc::new(tt::Subtree { value: CowArc::Owned(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(loc.call_site), delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
token_trees: Vec::new(), token_trees: Vec::new(),
}), }),
@ -718,7 +729,7 @@ fn macro_expand(
// As such we just return the input subtree here. // As such we just return the input subtree here.
MacroDefKind::BuiltInEager(..) if loc.eager.is_none() => { MacroDefKind::BuiltInEager(..) if loc.eager.is_none() => {
return ExpandResult { return ExpandResult {
value: macro_arg.clone(), value: CowArc::Arc(macro_arg.clone()),
err: err.map(|err| { err: err.map(|err| {
let mut buf = String::new(); let mut buf = String::new();
for err in &**err { for err in &**err {
@ -752,12 +763,17 @@ fn macro_expand(
// Skip checking token tree limit for include! macro call // Skip checking token tree limit for include! macro call
if !loc.def.is_include() { if !loc.def.is_include() {
// Set a hard limit for the expanded tt // Set a hard limit for the expanded tt
if let Err(value) = check_tt_count(&tt, loc.call_site) { if let Err(value) = check_tt_count(&tt) {
return value; return value.map(|()| {
CowArc::Owned(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
token_trees: vec![],
})
});
} }
} }
ExpandResult { value: Arc::new(tt), err } ExpandResult { value: CowArc::Owned(tt), err }
} }
fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> { fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<Arc<tt::Subtree>> {
@ -796,8 +812,13 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
); );
// Set a hard limit for the expanded tt // Set a hard limit for the expanded tt
if let Err(value) = check_tt_count(&tt, loc.call_site) { if let Err(value) = check_tt_count(&tt) {
return value; return value.map(|()| {
Arc::new(tt::Subtree {
delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
token_trees: vec![],
})
});
} }
fixup::reverse_fixups(&mut tt, &undo_info); fixup::reverse_fixups(&mut tt, &undo_info);
@ -819,14 +840,11 @@ fn token_tree_to_syntax_node(
mbe::token_tree_to_syntax_node(tt, entry_point) mbe::token_tree_to_syntax_node(tt, entry_point)
} }
fn check_tt_count(tt: &tt::Subtree, call_site: Span) -> Result<(), ExpandResult<Arc<tt::Subtree>>> { fn check_tt_count(tt: &tt::Subtree) -> Result<(), ExpandResult<()>> {
let count = tt.count(); let count = tt.count();
if TOKEN_LIMIT.check(count).is_err() { if TOKEN_LIMIT.check(count).is_err() {
Err(ExpandResult { Err(ExpandResult {
value: Arc::new(tt::Subtree { value: (),
delimiter: tt::Delimiter::invisible_spanned(call_site),
token_trees: vec![],
}),
err: Some(ExpandError::other(format!( err: Some(ExpandError::other(format!(
"macro invocation exceeds token limit: produced {} tokens, limit is {}", "macro invocation exceeds token limit: produced {} tokens, limit is {}",
count, count,

View file

@ -5,6 +5,7 @@ import * as vscode from "vscode";
import type { Env } from "./client"; import type { Env } from "./client";
import { log } from "./util"; import { log } from "./util";
import { expectNotUndefined, unwrapUndefinable } from "./undefinable"; import { expectNotUndefined, unwrapUndefinable } from "./undefinable";
import type { JsonProject } from "./rust_project";
export type RunnableEnvCfgItem = { export type RunnableEnvCfgItem = {
mask?: string; mask?: string;

View file

@ -23,6 +23,7 @@ import { execRevealDependency } from "./commands";
import { PersistentState } from "./persistent_state"; import { PersistentState } from "./persistent_state";
import { bootstrap } from "./bootstrap"; import { bootstrap } from "./bootstrap";
import type { RustAnalyzerExtensionApi } from "./main"; import type { RustAnalyzerExtensionApi } from "./main";
import type { JsonProject } from "./rust_project";
// We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
// only those are in use. We use "Empty" to represent these scenarios // only those are in use. We use "Empty" to represent these scenarios

View file

@ -6,6 +6,7 @@ import { type CommandFactory, Ctx, fetchWorkspace } from "./ctx";
import * as diagnostics from "./diagnostics"; import * as diagnostics from "./diagnostics";
import { activateTaskProvider } from "./tasks"; import { activateTaskProvider } from "./tasks";
import { setContextValue } from "./util"; import { setContextValue } from "./util";
import type { JsonProject } from "./rust_project";
const RUST_PROJECT_CONTEXT_NAME = "inRustProject"; const RUST_PROJECT_CONTEXT_NAME = "inRustProject";

View file

@ -1,4 +1,4 @@
interface JsonProject { export interface JsonProject {
/// Path to the directory with *source code* of /// Path to the directory with *source code* of
/// sysroot crates. /// sysroot crates.
/// ///
@ -21,7 +21,7 @@ interface JsonProject {
crates: Crate[]; crates: Crate[];
} }
interface Crate { export interface Crate {
/// Optional crate name used for display purposes, /// Optional crate name used for display purposes,
/// without affecting semantics. See the `deps` /// without affecting semantics. See the `deps`
/// key for semantically-significant crate names. /// key for semantically-significant crate names.
@ -82,7 +82,7 @@ interface Crate {
proc_macro_dylib_path?: string; proc_macro_dylib_path?: string;
} }
interface Dep { export interface Dep {
/// Index of a crate in the `crates` array. /// Index of a crate in the `crates` array.
crate: number; crate: number;
/// Name as should appear in the (implicit) /// Name as should appear in the (implicit)

View file

@ -2,7 +2,7 @@
"extends": "@tsconfig/strictest/tsconfig.json", "extends": "@tsconfig/strictest/tsconfig.json",
"compilerOptions": { "compilerOptions": {
"esModuleInterop": false, "esModuleInterop": false,
"module": "CommonJS", "module": "Node16",
"moduleResolution": "Node16", "moduleResolution": "Node16",
"target": "ES2021", "target": "ES2021",
"outDir": "out", "outDir": "out",