Caution

You’re reading a draft of the Ferrocene Language Specification. Some parts of this document might be missing, incomplete or incorrect. Our aim is to have the specification ready by the end of 2022.

14. Names and Resolution

Syntax

Name ::=
    Identifier

Legality Rules

14:1 An entity is a construct that can be referred to within a program by using a path.

14:2 A name identifies an entity within the program text.

14.1. Visibility

Syntax

VisibilityModifier ::=
    CratePublicModifier
  | SelfPublicModifier
  | SimplePathPublicModifier
  | SimplePublicModifier
  | SuperPublicModifier

CratePublicModifier ::=
    pub ( crate )

SelfPublicModifier ::=
    pub ( self )

SimplePathPublicModifier ::=
    pub ( in SimplePath )

SimplePublicModifier ::=
    pub

SuperPublicModifier ::=
    pub ( super )

Legality Rules

14.1:1 Visibility is a property of items that determines which modules can refer to a name of an item.

14.1:2 Public visibility is a kind of visibility that allows for a name to be referred to from arbitrary module M as long as the ancestor modules of the related entity can be referred to from M.

14.1:3 Private visibility is a kind of visibility that allows a name to be referred to only by the current module of the entity, and its descendant modules.

14.1:4 A visibility modifier sets the visibility of the name of an item.

14.1:5 A crate public modifier is a visibility modifier that grants a name public visibility within the current crate only.

14.1:6 A self public modifier is a visibility modifier that grants a name private visibility. A self public modifier is equivalent to a simple path public modifier where the simple path denotes keyword self.

14.1:7 A simple path public modifier is a visibility modifier that grants a name public visibility within the provided simple path only.

14.1:8 The simple path of a simple path public modifier shall start with a simple path segment expressed by either keyword crate, keyword self, or keyword super.

14.1:9 The simple path of a simple path public modifier shall resolve to an ancestor module of the current module or the current module itself.

14.1:10 A simple public modifier is a visibility modifier that grants a name public visibility.

14.1:11 A super public modifier is a visibility modifier that grants a name public visibility within the parent module only. A super public modifier is equivalent to a simple path public modifier where the simple path denotes keyword super.

14.1:12 An external item, a field, or an item that appears without a visibility modifier has private visibility by default.

14.1:13 An associated item of a trait with public visibility has public visibility by default.

14.1:14 An enum variant and its fields have the same visibility as the containing enum type.

Examples

pub mod outer_module {
    pub mod inner_module {
        pub(crate) fn crate_visible_function() {}

        pub(self) fn inner_module_visible_function() {}

        pub(super) fn outer_module_visible_function() {}

        pub fn visible_function() {}

        fn caller() {
            crate_visible_function();
            inner_module_visible_function();
            visible_function();
        }
    }

    fn caller() {
        inner_module::crate_visible_function();
        inner_module::outer_module_visible_function();
        inner_module::visible_function();
    }
}

fn caller() {
    outer_module::inner_module::crate_visible_function();
    outer_module::inner_module::visible_function();
}

14.2. Paths

Syntax

SimplePath ::=
    ::? SimplePathSegment (:: SimplePathSegment)*

SimplePathList ::=
    SimplePath (, SimplePath)* ,?

SimplePathSegment ::=
    Identifier
  | crate
  | $crate
  | self
  | super

PathInExpression ::=
    ::? PathInExpressionSegment (:: PathInExpressionSegment)*

PathInExpressionSegment ::=
    PathSegment (:: GenericArgumentList)?

PathSegment ::=
    Identifier
  | crate
  | $crate
  | self
  | Self
  | super

TypePath ::=
    ::? TypePathSegment (:: TypePathSegment)*

TypePathSegment ::=
    PathSegment ::? (GenericArgumentList | TypePathFn)?

TypePathFn ::=
    ( TypeSpecificationList? ) ReturnType?

QualifiedPathInExpression ::=
    QualifiedPathType (:: PathInExpressionSegment)+

QualifiedPathType ::=
    < TypeSpecification TypePathRenaming? >

TypePathRenaming ::=
    as TypePath

QualifiedPathInType ::=
    QualifiedPathType (:: TypePathSegment)+

Legality Rules

14.2:1 A path is a sequence of path segments logically separated by namespace qualifier :: that resolves to a name.

14.2:2 A path that starts with qualifier $crate shall appear only within a macro transcriber.

14.2:3 A simple path is a path whose path segments consist of either identifiers or certain keywords.

14.2:4 A global path is a path that starts with namespace qualifier ::.

14.2:5 A path segment is a constituent of a path.

14.2:6 Should talk about the effects of a QualifiedPathType with respect to generics.

14.2:7 A canonical path is a path that fully qualifies a name starting from the current crate.

14.2:8 The following constructs do not have a canonical path:

Examples

14.2:14 The following is a simple path. See Paragraph 14.2. for the declaration of crate_visible_function.

crate::outer_module::inner_module::crate_visible_function();

14.2:15 The following is a path-in-expression.

Vec::<u8>::with_capacity(42);

14.2:16 The following is a path-in-type.

std::boxed::Box<dyn std::ops::FnOnce(isize) -> size>;

struct S;
impl S {
    fn f() { println!("f of S"); }
}
trait T {
    fn f() { println!("f of T"); }
}
impl T for S {}

14.2:17 The following is a path-in-type. The call expression invokes T’s function.

<S as T>::f();

14.2:18 Add an example for qualified path-in-expression.

14.3. Use Imports

Syntax

UseImport ::=
    use UseImportContent ;

UseImportContent ::=
    GlobImport
  | NestingImport
  | SimpleImport

GlobImport ::=
    SimplePathPrefix? *

NestingImport ::=
    SimplePathPrefix? { UseImportContentList? }

SimpleImport ::=
    SimplePath Renaming?

SimplePathPrefix ::=
    SimplePath? ::

UseImportContentList ::=
    UseImportContent (, UseImportContent)* ,?

Legality Rules

14.3:1 A use import brings names into scope within the module or block expression where the use import resides.

14.3:2 A glob import is a use import that brings all names with public visibility prefixed by its path prefix into scope.

14.3:3 A glob import shall contain a simple path.

14.3:4 A nesting import is a use import that provides a common path prefix for its nested use imports.

14.3:5 A simple import is a use import that binds a simple path to a local name by using an optional renaming.

14.3:6 use self as foo -> imports the current module under the name “foo”

14.3:7 use blah::{self} -> imports “blah”

14.3:8 use blah::{self as foo} -> imports blah under the name “foo”

14.3:9 use blah::gah::{self} -> imports “gah”

14.3:10 use blah::{gah::{self as foo}} -> imports gah under the name “foo”

14.3:11 The above imports the names in the type namespace only

14.3:12 When keyword self appears by itself in a use import, then the use import shall be a simple import with a renaming.

14.3:13 When keyword crate

14.3:14 A use import with public visibility is said to re-export imported names. What does this do exactly? What are the effects?

Examples

14.3:15 The following is a glob import. See Paragraph 14.2. for the declaration of modules and functions. The imported functions are create_visible_function, outer_module_visible_function, visible_function.

use outer_module::inner_module::*;

14.3:16 The following is a renaming import. The imported function is visible_function under the name f.

use outer_module::inner_module::visible_function as f;

14.3:17 The following is a selective import. The imported functions are crate_visible_function and visible_function.

use outer_module::inner_module::{crate_visible_function, visible_function}

14.4. Scopes

14.4:1 Rust

Legality Rules

14.4:2 A scope is a region of program text where a name can be referred to. A name is in scope when it can be referred to.

14.4:3 How are hierarchies of scopes formed?

14.4.1. Associated Item Scope

Legality Rules

14.4.1:1 The name of an associated item is never in scope.

14.4.2. Binding Scopes

Legality Rules

14.4.2:1 The binding of a closure parameter is in scope within the related closure body.

14.4.2:2 The binding of a function parameter is in scope within the related function body.

14.4.2:3 The binding of a for loop or a while let loop is in scope within the related loop body.

14.4.2:4 The binding of an if let expression is in scope within the related block expression.

14.4.2:5 The binding of a let statement is in scope after the related let statement until the end of the block expression where the related let statement appears.

14.4.2:6 The binding of a match arm is in scope within its related expressions and related match arm guard.

14.4.3. Declarative Macro Scope

Legality Rules

14.4.3:1 The name of a declarative macro is in scope after the related macro rules declaration until the end of the block expression or the enclosing module where the macro rules declaration appears.

14.4.4. Generic Parameter Scope

Legality Rules

14.4.4:1 The name of a generic parameter of a construct is in scope within the related construct.

14.4.4:2 The name of a generic parameter is not in scope within items declared inside a function.

14.4.5. Item Scope

Legality Rules

14.4.5:1 The name of an item declared within a module is in scope within the related module. Such a name is not in scope within nested modules.

14.4.5:2 The name of an item declared within a block expression is in scope within the related block expression.

14.4.5:3 It is a static error to declare an item within a block expression or a module where the name of the item is already used by another item within the same block expression or module.

14.4.6. Lifetime Parameter Scope

Legality Rules

14.4.6:1 The name of a lifetime parameter is in scope within the related implementation, function, or trait. (merge into Generic Parameter Scopes?)

14.4.6:2 The name of a lifetime parameter is not in scope in constants and statics. (isn’t this redundant?)

14.4.7. Loop Label Scope

Legality Rules

14.4.7:1 The label of a loop expression is in scope from its declaration until the end of the related loop expression.

14.4.7:2 The label of a loop expression is not in scope in async blocks, closures, constant arguments, constant contexts, items, and the iterator expression of the related for loop.

14.4.8. Prelude Scopes

Legality Rules

14.4.8:1 Prelude names are in scope of every module.

14.4.9. Self Scope

Legality Rules

14.4.9:1 The Self type is in scope within abstract data types, implementations, and traits.

14.4.10. Trait Bound Scopes

Legality Rules

14.4.10:1 Could you translate this (I never understood higher-ranked trait bounds)?

14.4.10:2 The scope of a lifetime parameter declared as a [higher-ranked trait bound][hrtb] depends on the scenario where it is used.

14.4.10:3 As a [_TypeBoundWhereClauseItem_] the declared lifetimes are in scope in the type and the type bounds.

14.4.10:4 As a [_TraitBound_] the declared lifetimes are in scope within the bound type path.

14.4.10:5 As a [_BareFunctionType_] the declared lifetimes are in scope within the function parameters and return type.

14.5. Shadowing

Legality Rules

14.5:1 Shadowing is a property of names. A name is said to be shadowed when another name with the same characters is introduced in the same scope within the same namespace, effectively hiding it. A name cannot be referred to by any means once it is shadowed.

14.5:2 The name of built-in attributes shall not be shadowed.

14.5:3 The name of a generic parameter shall not be shadowed.

14.5:4 The name of an item declared within a module may shadow a prelude name. (is this rule needed?)

14.5:5 A binding shall not shadow the name of a constant parameter, a constant, an enum constructor, a static, or a struct constructor.

14.5:6 A prelude name shadows other prelude names depending on which preludes are included in a module. The order of shadowing is as follows, where a later prelude name shadows earlier prelude name:

  1. 14.5:7 Language prelude names.

  2. 14.5:8 Standard library prelude names.

  3. 14.5:9 macro_use prelude names.

  4. 14.5:10 Tool prelude names.

  5. 14.5:11 External prelude names.

14.6. Namespaces

Legality Rules

14.6:1 A namespace is a logical grouping of names. Names are segregated into separate namespaces based on the kind of entity the name belongs to. Within a namespace, names are organized into a hierarchy of scopes.

14.6:2 A namespace is classified as either an anonymous namespace, a label namespace, a lifetime namespace, a macro namespace, a type namespace, or a value namespace.

14.6:3 A label namespace contains the names of the following entities:

14.6:5 A lifetime namespace contains the names of the following entities:

14.6:7 A macro namespace contains the names of the following entities:

14.6:13 A type namespace contains the names of the following entities:

14.6:29 A value namespace contains the names of the following entities:

14.6:41 The names of the following entities are not part of any namespace:

14.7. Preludes

Legality Rules

14.7:1 A prelude is a collection of names that are automatically brought in scope of every module in a crate. Such names are referred to as prelude names.

14.7:2 The core prelude is a prelude that ???.

14.7:3 An external prelude is a prelude that brings in scope of the root module the names of the crates imported using external crate imports. If the external crate import uses a renaming, then the renaming is instead added to the external prelude. The core crate is always added to the external prelude unless the crate root is subject to attribute no_core.

14.7:4 The language prelude is a prelude that brings in scope of every module the following names:

14.7:10 The macro_use prelude is a prelude that brings in scope of the root module the names of macros from external crates that were imported using an external crate import.

Legality Rules

14.8. Name Resolution

Legality Rules

14.8:1 Name resolution is the process of relating a path to a name by considering namespaces, scopes, and visibility. A path that is successfully related to a name is said to be resolved.

14.8:2 Containment name resolution is a kind of name resolution that relates the identifier of a path segment to a name that is expected to be defined in a given module, as follows:

  1. 14.8:3 Make the scope of the given module where the identifier resides be the current scope.

  2. 14.8:4 If the given module contains a name that matches the characters of the identifier, then relate the identifier to the matched name.

  3. 14.8:5 Otherwise this is a static error.

14.8:6 Macro name resolution is a kind of name resolution that relates the identifier of a path segment to the name of a declarative macro as follows:

  1. 14.8:7 Make the scope where the identifier resides be the current scope.

  2. 14.8:8 While there is a current scope

    1. 14.8:9 If the current scope contains a name of a declarative macro that matches the characters of the identifier, then

      1. 14.8:10 Relate the identifier to the matched name.

      2. 14.8:11 Stop the macro name resolution.

    2. 14.8:12 Otherwise make the current scope be the enclosing scope of the current scope.

  3. 14.8:13 If the macro scope contains a name of a declarative macro that matches the characters of the identifier, then relate the identifier to the matched name.

  4. 14.8:14 Otherwise this is a static error.

14.8:15 Nearest enclosing name resolution is a kind of name resolution that relates the identifier of a path segment to a name that is expected to be declared in a given namespace, as follows:

  1. 14.8:16 Make the scope of the given namespace where the identifier resides be the current scope.

  2. 14.8:17 While there is a current scope

    1. 14.8:18 If the current scope contains a name that matches the characters of the identifier, then

      1. 14.8:19 Relate the identifier to the matched name.

      2. 14.8:20 Stop the nearest enclosing name resolution.

    2. 14.8:21 Otherwise make the current scope be the enclosing scope of the current scope.

  3. 14.8:22 If the prelude scope contains a name that matches the characters of the identifier, then relate the identifier to the matched name.

  4. 14.8:23 Otherwise this is a static error.

14.8:24 Type name resolution is a kind of name resolution that relates the identifier of a path segment to a name that is expected to be declared in an implementation of a type, as follows:

  • 14.8:25 Explain

  • 14.8:26 I can’t figure out how to hook this into the algorithm below

14.8:27 If a path consists of multiple path segments, then the path is resolved as follows:

  1. 14.8:28 Make the first path segment be the current path segment.

  2. 14.8:29 Perform nearest enclosing name resolution, where the path segment is the current path segment and the namespace is the type namespace.

  3. 14.8:30 If the current path segment did not resolve to a module, then this is a static error.

  4. 14.8:31 Make the current path segment be the previous path segment.

  5. 14.8:32 Make the next path segment be the current path segment.

  6. 14.8:33 While the current path segment is not the last path segment

    1. 14.8:34 Perform containment name resolution, where the path segment is the current path segment and the module is the module that the previous path segment resolved to.

    2. 14.8:35 If the current path segment did not resolve to a module, then this is a static error.

    3. 14.8:36 Make the current path segment be the previous path segment.

    4. 14.8:37 Make the next path segment be the current path segment.

  7. 14.8:38 Perform containment name resolution, where the path segment is the current path segment and the module is the module that the previous path segment resolved to. (more?)

14.8:39 It is a static error if a path that consists of multiple path segments cannot be related to a name of an item.

14.8:40 A global path is resolved starting from the external prelude.

14.8:41 If a path starts with qualifier crate, then the path is resolved relative to the current crate.

14.8:42 If a path starts with qualifier $crate, then the path is resolved relative to the crate where the related macro is declared.

14.8:43 If a path starts with qualifier self, then the path is resolved relative to the current module.

14.8:44 If a path starts with qualifier Self, then the path is resolved relative to the implementing type within an implementation or a trait.

14.8:45 If a path starts with qualifier super, then the path is resolved relative to the parent module.

14.8:46 If a path consists of a single path segment, then the path is resolved as follows:

  1. 14.8:47 Make the first path segment be the current path segment.

  2. 14.8:48 Perform nearest enclosing name resolution where the path segment is the current path segment, and the namespace is which one???.

14.8:49 It is a static error if a path that consists of a single path segment cannot be related to the name of a locally declared item or a locally declared variable.

14.8:50 A macro invocation is resolved using macro name resolution.