Skip to main content

BuiltinProvider

Struct BuiltinProvider 

Source
pub struct BuiltinProvider { /* private fields */ }
Expand description

The provider that reads declaration files with this crate’s own oracle.

Implementations§

Source§

impl BuiltinProvider

Source

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.

Source

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.

Source

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.

Source

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

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Hand-written because neither TypeScriptSupport nor tree_sitter::Parser is Debug, the same reason and the same shape as the oracle’s own impl.

Source§

impl TypeProvider for BuiltinProvider

Source§

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

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>

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 type_of(&self, q: Query<'_>) -> Option<Type>

The type of the expression at q.node.
Source§

fn symbol_of(&self, q: Query<'_>) -> Option<Symbol>

Where the name at q.node came from.
Source§

fn return_type_of(&self, q: Query<'_>) -> Option<Type>

What calling the function at q.node yields. Read more
Source§

fn identity(&self) -> Vec<u8>

What this provider is, for the cache key. Read more
Source§

fn revalidate(&self, files: &FileAccess)

Drop whatever this provider holds that the files no longer support. Read more
Source§

fn dependency_paths(&self) -> BTreeSet<FilePath>

Every path this provider’s own dependency mechanism named for the run it last prepared. Read more
Source§

fn failure(&self) -> Option<BeginRunError>

The first error this provider produced, if it has produced one. Read more
Source§

fn notices(&self) -> Vec<String>

Lines this provider wants said about the run it has just prepared. Read more
Source§

fn needs_rebuild(&self) -> bool

Whether this provider is past repair and has to be built again. Read more
Source§

fn spends_analysis_budget(&self) -> bool

Whether this provider spends the run’s AnalysisBudget. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.