Skip to main content

Interface

Struct Interface 

Source
pub struct Interface {
    pub module_name: ModuleName,
    pub values: HashMap<Name, ValueSignature>,
    pub unions: HashMap<Name, UnionType>,
    pub opaque_unions: HashSet<Name>,
    pub infixes: HashMap<Name, Infix>,
    pub infix_functions: HashMap<Name, ValueSignature>,
    pub arities: HashMap<Name, usize>,
    pub classes: HashMap<Name, ClassSignature>,
    pub instances: Vec<PublishedInstance>,
    pub file: Option<SourceFileId>,
    pub incomplete: bool,
}
Expand description

An interface is trim down version of a module.

We use it when translating a local source AST into its canonical form as an optimization technique. Instead of parsing every source files on each file compilation, we save the publicly exposed information of a successfully parsed module and only load this information on module depending on it.

All Interface indices are using non-qualified names. To get the qualified version, simply use I.module_name.qualify_name(&name).

Fields§

§module_name: ModuleName§values: HashMap<Name, ValueSignature>

Each value’s type and the context its annotation wrote, with where its declaration was written: a canonical::ValueSignature.

§unions: HashMap<Name, UnionType>

Every union type the module exposes, opaquely or not. An opaque one — see opaque_unions — is here with its variants emptied.

§opaque_unions: HashSet<Name>

The names in unions that the module exposes opaquely: a bare Size in its exposing header rather than Size(..).

An opaque entry’s variants is empty, and so is that of a type declared with no constructors at all (type Empty =, which the grammar accepts today and LANG-10 is to reject), so variants alone cannot say whether the constructors were withheld. This set is what says it. canonical::environment::process_import reads it to reject a Size(..) import entry for such a type, and default_imports to leave out a default import asking for constructors the module does not expose.

canonical::Module::to_interface fills it. A hand-built interface that leaves it empty exposes every union it holds with whatever variants it carries.

§infixes: HashMap<Name, Infix>

infixes is a map from the operator symbol to its information

§infix_functions: HashMap<Name, ValueSignature>

The signature of an exposed infix’s own backing function, keyed by that function’s unqualified name — populated only when the function is not separately present in values, i.e. the header exposes the operator but not the function by name (infix left 6 (+) = add, header exposing (+) and not add, is std/core’s own shape for every operator it declares).

canonical::environment::imported_infix is what needs it: an operator is resolved through its infix declaration, and the declaration alone names the backing function without saying anything about its type. Whichever of the two maps holds it, that is where the type comes from — and for an operator whose function is not separately exposed, this is the only one that can.

Nothing else reads it, and in particular nothing inserts it into an importing module’s scope under its own name: a function that backs an exposed operator is importable by name only when the header says so too (BUG-9), and then it is values that carries it.

§arities: HashMap<Name, usize>

How many parameters each value in values and infix_functions is emitted with, keyed the same way: canonical::Module::emitted_arity.

An importer reads it for the same reason the module declaring the value reads its own declarations’ arities: a call supplying that many arguments is a direct call, and a partial application, or a use as a value of one taking two or more, goes through the runtime’s $curry (DEC-18 decision 3). The typer’s translation is where it is read, into ir::ReferenceKind::Foreign.

canonical::Module::to_interface records one for every value either map holds, except a value its module recorded in canonical::Module::broken, whose parameters are unknown. A value missing from it — a broken one, or one a hand-built interface in a test leaves out — is read as arity 0, the arity of a parameterless binding.

§classes: HashMap<Name, ClassSignature>

Every class the module declares and exposes, by name, with its members and the derivations it carries, which are what an importer writes a derived instance’s members out of. A member is not in values: an importer reaches it through its class.

§instances: Vec<PublishedInstance>

Every instance in scope in the module: the ones it declares, and every one an import brought into it.

The one part of an interface the module’s exposing header does not filter. An instance has no name an importer could write, and it is in scope wherever its class and its type are, so it travels through every import, transitively, whether or not the importer named anything (Type classes). Each entry records the module that declared it, which is what recognises the same instance arriving by two routes as one.

§file: Option<SourceFileId>

The file this interface’s module was read from, when the caller knows it.

It is what makes a diagnostic about an imported name able to underline that name’s own source rather than merely naming its module. Nothing inside a module check can supply it: a phase only ever sees one module and never learns its SourceFileId (see PhaseError). Driver code does, so canonical::Module::to_interface takes it as an argument, and its one caller — dependencies::ModuleWalker::check_in_order, which like check_package is a driver loop and already holds the file each module came from — passes it there. A hand-built interface, as every test below check_module constructs, passes None; Interface::source_span then has no file to pair a span with and returns None, so the diagnostic degrades to no secondary label rather than a wrong one.

§incomplete: bool

A name looked up in this interface and not found may be one its module declares and could not publish.

canonical::Module::to_interface copies the module’s own incomplete, which is set when the module’s scope was incomplete or when a declaration’s annotation did not canonicalize or may be a chunk that failed to parse. Interface::unavailable, the stand-in for a module whose header did not parse, sets it. An importer that names something this interface lacks reports nothing about it, because the failure that made the name missing has already been reported against the module (DEC-23 decision 3), and the importer’s own scope is incomplete in turn. A hand-built interface leaves it false.

Implementations§

Source§

impl Interface

Source

pub fn unavailable(module_name: ModuleName, file: SourceFileId) -> Interface

The interface of a module whose header did not parse: it holds nothing, and is incomplete, so an importer finds the module and reports nothing about what it does not find in it. file is the file the module was read from.

The header’s syntax error is the one that stands behind every name missing from it, and is reported with the package, which therefore publishes nothing: the stand-in is only ever seen by the modules of its own package.

Source

pub fn source_span(&self, span: NodeSpan) -> Option<SourceSpan>

Pair a [NodeSpan] taken from this interface’s own data — a value’s declaration, a canonical::UnionType’s or canonical::Infix’s span field — with the file it was written in, when both halves are known.

Both halves are needed: a NodeSpan with nothing behind it (a hand-built test value) or an interface with no attached file (same) leaves nothing honest to build, and None is that answer — the caller renders no label rather than one pointing at byte 0 of the wrong file.

Trait Implementations§

Source§

impl Clone for Interface

Source§

fn clone(&self) -> Interface

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Interface

Source§

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

Formats the value using the given formatter. 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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.