degory / ghul

compiler for the ghūl programming language
https://ghul.dev
GNU Affero General Public License v3.0
4 stars 0 forks source link

Support importing symbols into classes and functions #1137

Open degory opened 6 months ago

degory commented 6 months ago

Global symbols from other namespaces can be imported into the current namespace with use but use does not work within classes, traits or structs, or withing functions or methods.

With the introduction of tagged union types with variants (#1132) it would be useful not to have to repeatedly write out potentially wordy qualified variant names. It would also be good not to have to repeatedly write out actual generic arguments.

Add support for use definitions in the bodies of classes, traits and structs. Add support for use statements in statement lists in function and method bodies Add support for use ... in expressions

These new kinds of use (but not global use) should allow generic arguments where appropriate, to support importing a particular specialization of a generic type.

In resolve explicit types, if the type part of use {alias} = {type} is simply a qualified identifier then it's OK for it not to resolve to a type.

union Option[T] is
    SOME(value: T);
    NONE;
si

class TEST[T] is
    use Option[T]; // bring Option[T].SOME and Option[T].NONE into scope
    use Option = Option[T]; // bring Option[T] into scope as Option

    _opt: Option;
    _some: SOME;
    _none: NONE;

    init(opt: Option, some: SOME) is
        ...
    si

    init(val: T) is
       _opt = new SOME(val)
    si
si

union Tree[T] is
    NODE(left: Tree[T], right: Tree[T]);
    LEAF(value: T);
si

create_tree[T](next_value: () -> T) is
    use Tree[T].NODE;
    use Tree[T].LEAF;

    return new NODE(new LEAF(next_value()), new LEAF(next_value()));
si

We could treat an import of a generic type as both an import of its members and re-binding of its name to the given generic specialization:

use Option[T]

Could be taken to mean

use Option = Option[T]
use Option (i.e. import SOME and NONE)

but this would have the potentially surprising and annoying effect of hiding Option[T]

It's not immediately clear at what point in the compile process we would need to apply these kinds of use. We need to be able to resolve the referenced types, which means global symbols need to have been declared. But we also want the types to be available to member definitions, including as the types of fields and properties, as method return types and as argument types.

It could be that they can be handled in the resolve-explicit-types phase, particularly as we don't need to support forward definitions (i.e. the use of a type must precede any reference to it in subsequent definitions)

Conceptually, use could be treated as a macro that expands to the referenced type, which implies we can resolve use without adding another pass

Global use imports symbols referenced by qualified identifiers. These new kinds of use will need to import types. The syntax for types includes qualified identifiers, so it would be a non-breaking change to also support import of types from a global use. Howver, Given when the resolve-uses pass is run, it's possible this would just work.