summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-check-decl.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2020-08-20 08:23:51 -0700
committerGitHub <noreply@github.com>2020-08-20 08:23:51 -0700
commit11748a75e66c2bd3fa7ef7635fd35363465f599c (patch)
treec1920f54ac59dcd79806b475df3e4c1ba85756ba /source/slang/slang-check-decl.cpp
parentb5a4161a801a573179b1f552e5c53748d2667b03 (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.cpp54
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