diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2020-08-20 08:23:51 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-08-20 08:23:51 -0700 |
| commit | 11748a75e66c2bd3fa7ef7635fd35363465f599c (patch) | |
| tree | c1920f54ac59dcd79806b475df3e4c1ba85756ba /source/slang/slang-check-decl.cpp | |
| parent | b5a4161a801a573179b1f552e5c53748d2667b03 (diff) | |
Initial support for a using construct (#1506)
The basic idea is that if you have a namespace:
namespace MyCoolNamespace { void f() { ... } ... }
then you can bring the declarations from that namespace into scope with:
using MyCoolNamespace;
f();
The `using` construct is allowed in any scope where declarations are allowed. As an additional feature, the construct allows and then ignores the keyword `namespace` if it occurs right after `using`:
using namespace MyCoolNamespace;
Note that unlike in C++, `using` a namespace inside another namespace doesn't implicitly make the symbols available to clients of that namespace:
namespace hidden { void secret() {...} ... }
namespace api { using hidden; ... }
api.secret(); // ERROR: `secret()` isn't a member of `api`
The implementation of this feature was relatively simple, although it does leave out more advanced features that might be desirable in the future:
* No support for `using MCN = MyCoolNamespace` sorts of tricks to define a short name
* No support for `using` anything that isn't a namespace (e.g., to make the members of a type available without qualification)
* No support for cases where multiple visible modules have a namespace of the same name (or dealing with overloaded namespaces in general)
Diffstat (limited to 'source/slang/slang-check-decl.cpp')
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 10e3818c4..4ea8aa7f6 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -56,6 +56,8 @@ namespace Slang void visitImportDecl(ImportDecl* decl); + void visitUsingDecl(UsingDecl* decl); + void visitGenericTypeParamDecl(GenericTypeParamDecl* decl); void visitGenericValueParamDecl(GenericValueParamDecl* decl); @@ -4615,6 +4617,58 @@ namespace Slang } } + void SemanticsDeclHeaderVisitor::visitUsingDecl(UsingDecl* decl) + { + // First, we need to look up whatever the argument of the `using` + // declaration names. + // + decl->arg = CheckTerm(decl->arg); + + // Next, we want to ensure that whatever is being named by `decl->arg` + // is a namespace (or a module, since modules are namespace-like). + // + // TODO: The logic here assumes that we can't have multiple `NamespaceDecl`s + // with the same name in scope, but that assumption is only valid in the + // context of a single module (where we deduplicate `namespace`s during + // parsing). If a user `import`s multiple modules that all have namespaces + // of the same name, it would be possible for `decl->arg` to be overloaded. + // In that case we should really iterate over all the entities that are + // named and import any that are namespace-like. + // + NamespaceDeclBase* namespaceDecl = nullptr; + if( auto declRefExpr = as<DeclRefExpr>(decl->arg) ) + { + if( auto namespaceDeclRef = declRefExpr->declRef.as<NamespaceDeclBase>() ) + { + SLANG_ASSERT(!namespaceDeclRef.substitutions.substitutions); + namespaceDecl = namespaceDeclRef.getDecl(); + } + } + if( !namespaceDecl ) + { + getSink()->diagnose(decl->arg, Diagnostics::expectedANamespace, decl->arg->type); + return; + } + + // Once we have identified the namespace to bring into scope, + // we need to create a new sibling sub-scope to add to the + // lookup scope that was in place when the `using` was parsed. + // + // Subsequent lookup in that scope will walk through our new + // sub-scope and see the namespace. + // + // TODO: If we update the `containerDecl` in a scope to allow + // for a more general `DeclRef`, or even a full `DeclRefExpr`, + // then it would be possible for `using` to apply to more kinds + // of entities than just namespaces. + // + auto scope = decl->scope; + auto subScope = new Scope(); + subScope->containerDecl = namespaceDecl; + subScope->nextSibling = scope->nextSibling; + scope->nextSibling = subScope; + } + /// Get a reference to the candidate extension list for `typeDecl` in the given dictionary /// /// Note: this function creates an empty list of candidates for the given type if |
