pub struct BuiltinProvider { /* private fields */ }Expand description
The provider that reads declaration files with this crate’s own oracle.
Implementations§
Source§impl BuiltinProvider
impl BuiltinProvider
Sourcepub fn probe(language: &dyn Language) -> Option<Self>
pub fn probe(language: &dyn Language) -> Option<Self>
Confirm a grammar speaks TypeScript and build a provider over it, with no second
grammar — Self::probe_with is where one is added.
None on the same two conditions TypeScriptSupport::probe refuses on — a grammar
without the vocabulary this oracle reads, or a language with no binding resolver —
plus a third: a grammar the parser will not accept at all. Each would otherwise
produce confident nonsense rather than an error.
The only constructor. A provider must parse declaration files, so it cannot be built from a resolver alone.
Sourcepub fn probe_with(
language: &dyn Language,
tsx: Option<&dyn Language>,
) -> Option<Self>
pub fn probe_with( language: &dyn Language, tsx: Option<&dyn Language>, ) -> Option<Self>
Self::probe with a second grammar, for the .tsx files the resolver reaches.
The oracle’s vocabulary is still confirmed against the main language alone, and the
support built from it is what answers every question: the tsx grammar speaks the same
node vocabulary — it is the same resolver, one grammar wider — so a .tsx sibling
needs no second oracle, only a second parse.
None when either grammar will not load into a parser, the main probe’s own refusal
unchanged: a resolver that reaches a .tsx file a provided grammar cannot parse is
one that would answer from ERROR nodes.
Sourcepub fn declaration(
&self,
files: &FileAccess,
path: &FilePath,
) -> Option<Arc<Declaration>>
pub fn declaration( &self, files: &FileAccess, path: &FilePath, ) -> Option<Arc<Declaration>>
The parsed declaration file at path, parsed once per version of its bytes — kept
across begin_run now, not cleared to force a re-parse per run.
None when nothing is there, when it is not text, or when the grammar refuses it —
three different reasons and one answer, because a rule can do nothing different with
any of them and a rule that branched on the difference would give different answers on
different machines.
One hash lookup per call, and bytes only when the parse is stale. The cache is
keyed by path, and two FileAccesses over one path can see two different files — a
rewrite mid-run, which is routine under --watch. Served by path alone, the second
importer would get the first version’s parse while its own access recorded the new
bytes’ hash, and the entry written then describes neither version: a wrong answer that
validates forever. So the hash decides, and FileAccess::hash_of answers it from the
access’s own memo without materializing the text — which is what the previous spelling
paid, cloning a whole declaration file per importer and re-hashing it to compare
against a digest the parse already carried.
Nothing memoizes the failures, and nothing needs to. A path with no hash is
re-probed on the next call, which costs one FileAccess::hash_of — and that access
has a memo of its own, so within a run the second probe reads nothing from the disk.
A memo here could only be keyed by path, having no hash to key on, so it would have to
be cleared wholesale at the start of every run to keep a .d.ts installed between two
runs from staying missing forever.
A path that has stopped answering — deleted, or no longer text — has its parse
dropped rather than left behind. The entry is unservable from here on, because every
path through this method compares a hash first, so keeping it holds a whole declaration
file’s tree and source until the next begin_run for nothing.
Sourcepub fn export_target(
&self,
files: &FileAccess,
file: &FilePath,
name: &str,
) -> Option<ExportTarget>
pub fn export_target( &self, files: &FileAccess, file: &FilePath, name: &str, ) -> Option<ExportTarget>
Follow name from file through re-exports to the file and name that declare it.
None when a link cannot be read, when the name is nowhere, or when the chain
exceeded MAX_EXPORT_DEPTH — one answer for the three, because a rule can do
nothing different with any of them. complete() can, and asks export_walk instead.
Trait Implementations§
Source§impl Debug for BuiltinProvider
impl Debug for BuiltinProvider
Source§impl TypeProvider for BuiltinProvider
impl TypeProvider for BuiltinProvider
Source§fn is_assignable_to(
&self,
q: Query<'_>,
module: &str,
name: &str,
) -> Option<bool>
fn is_assignable_to( &self, q: Query<'_>, module: &str, name: &str, ) -> Option<bool>
Whether the type at q.node is the type module exports as name, or declares a
relationship to it — extends or implements — across files, through aliases of the
named type. See TypeProvider::is_assignable_to for the full contract, including
its narrowings (declaration merging, a generic annotation at the use site, and an
unexported target name) and its documented gap (no function-local scoping — a
shadowing declaration inside a function is not distinguished from the top-level one).
Source§fn complete(&self, q: Query<'_>) -> bool
fn complete(&self, q: Query<'_>) -> bool
Whether every import in q’s file resolved to a declaration this provider could read.
Eager rather than lazy: every specifier is resolved here, not only the ones a rule happened to ask about, because a miss has to be recorded as a dependency even when nothing went looking for the type behind it — the cache’s own read on this file must see every candidate path an import could have named, so that a declaration appearing later invalidates a rule that stayed silent for its absence. Memoized per file, since several rules ask the same question about the same file within one run.
One thing it deliberately does not count: a specifier that is not code — ./app.css,
./data.json, ./logo.svg — is skipped entirely, probes and all. It is not a module
this oracle reads, and counting it would label most of a bundler’s project incomplete
for having stylesheets.
The contract is resolve-and-parse, judged per declaration where one is reached.
tree_sitter::Parser::parse answers a tree for any UTF-8 input, so a file this
provider could not fully read shows up only as parse faults — ERROR nodes, and the
MISSING tokens an unclosed brace leaves — and the whole-file verdict this once asked
let one damaged statement mark every importer of the file incomplete, project-wide,
throwing away the declarations outside the damaged span that answer normally (#229).
Each named import is walked to the node that declares it, through re-exports like
every other arm, and the name is unread when a link of that chain could not be read:
a specifier that resolves to nothing, a file that will not parse, a reached
declaration whose own subtree the parser did not finish (has_error() on the node,
which counts both kinds of fault), or a file in a dialect this provider has no grammar
for, which it does not read at all. A walk that ends on a clean module with no
export it can model is not unread — export = X beside declare namespace X is that
shape for every member of X, and counting it silenced every rule on every file
naming one (the #232 review). A nameless import — a side-effect one, or a namespace
binding, or export * — has no single node to reach: a side-effect import asserts the
module’s whole shape and a namespace import binds a module object whose members can
be anything, so both keep the whole-file verdict.
Source§fn begin_run(
&self,
files: &dyn Fn() -> Vec<FilePath>,
budget: AnalysisBudget,
) -> Result<Vec<u8>, BeginRunError>
fn begin_run( &self, files: &dyn Fn() -> Vec<FilePath>, budget: AnalysisBudget, ) -> Result<Vec<u8>, BeginRunError>
Start a run, and answer no key term.
Only completeness is cleared here. It carries no hash to compare against — a
verdict over a whole file’s imports, not a single read — so a provider held across
requests (#191) would otherwise answer a second run from the first run’s filesystem: a
file whose imports did not resolve would stay incomplete forever. declarations is
not cleared: it is keyed by content hash, Self::declaration compares that hash on
every access, and a stale entry is therefore never served whether or not this method
touched it. Clearing it here would only cost the parse back — and for a held provider,
re-paying that cost every request is the exact overhead holding the provider exists to
remove. Self::revalidate is what drops a hash-mismatched entry proactively, ahead
of declaration() finding out the hard way.
The file list is never asked for: this provider’s dependencies are the tracked reads
on each entry, so there is nothing to build up front. Answering an empty term is what
keeps the builtin provider out of analysis_hash’s programs field.
Source§fn return_type_of(&self, q: Query<'_>) -> Option<Type>
fn return_type_of(&self, q: Query<'_>) -> Option<Type>
q.node yields. Read moreSource§fn revalidate(&self, files: &FileAccess)
fn revalidate(&self, files: &FileAccess)
Source§fn dependency_paths(&self) -> BTreeSet<FilePath>
fn dependency_paths(&self) -> BTreeSet<FilePath>
Source§fn failure(&self) -> Option<BeginRunError>
fn failure(&self) -> Option<BeginRunError>
Source§fn notices(&self) -> Vec<String>
fn notices(&self) -> Vec<String>
Source§fn needs_rebuild(&self) -> bool
fn needs_rebuild(&self) -> bool
Source§fn spends_analysis_budget(&self) -> bool
fn spends_analysis_budget(&self) -> bool
AnalysisBudget. Read more