summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2020-04-02 08:52:42 -0700
committerGitHub <noreply@github.com>2020-04-02 08:52:42 -0700
commit487d4a4f406c9dd9803ecdca02467d09ee1ecf4a (patch)
treec1a64a26620de90636f16fa0fdb117f3a3c4f92e /source/slang
parent5e73e984022c9ec8e901ccffc94d3cd5f374642a (diff)
Add basic support for namespaces (#1304)
This change adds logic for parsing `namespace` declarations, referencing them, and looking up their members. * The parser changes are a bit subtle, because that is where we deal with the issue of "re-opening" a namespace. We kludge things a bit by re-using an existing `NamespaceDecl` in the same parent if one is available, and thereby ensure that all the members in the same namespace can see on another. * In order to allow namespaces to be referenced by name they need to have a type so that a `DeclRefExpr` to them can be formed. For this purpose we introduce `NamespaceType` which is the (singleton) type of a reference to a given namespace. * The new `NamespaceType` case is detected in the `MemberExpr` checking logic and routed to the same logic that `StaticMemberExpr` uses, and the static lookup logic was extended with support for looking up in a namespace (a thin wrapper around one of the existing worker routines in `slang-lookup.cpp`. * I made `NamespaceDecl` have a shared base class with `ModuleDecl` in the hopes that this would allow us to allow references to modules by name in the future. That hasn't been tested as part of this change. * I cleaned up a bunch of logic around `ModuleDecl` holding a `Scope` pointer that was being used for some of the more ad hoc lookup routines in the public API. Those have been switched over to something that is a bit more sensible given the language rules and that doesn't rely on keeping state sititng around on the `ModuleDecl`. * I added a test case to make sure the new funcitonality works, which includes re-opening a namespace, and it also tests both `.` and `::` operations for lookup in a namespace. * The main missing feature here is the ability to do something like C++ `using`. It would probably be cleanest if we used `import` for this, since we already have that syntax (and having both `import` and `using` seems like a recipe for confusion). Most of the infrastructure is present to support `import`ing one namespace into another (in a way that wouldn't automatically pollute the namespace for clients), but some careful thought needs to be put into how import of namespaces vs. modules should work.
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang-check-decl.cpp10
-rw-r--r--source/slang/slang-check-expr.cpp41
-rw-r--r--source/slang/slang-check-shader.cpp60
-rw-r--r--source/slang/slang-compiler.h7
-rw-r--r--source/slang/slang-decl-defs.h18
-rw-r--r--source/slang/slang-lookup.cpp29
-rw-r--r--source/slang/slang-lookup.h8
-rw-r--r--source/slang/slang-lower-to-ir.cpp31
-rw-r--r--source/slang/slang-parser.cpp192
-rw-r--r--source/slang/slang-syntax.cpp39
-rw-r--r--source/slang/slang-syntax.h4
-rw-r--r--source/slang/slang-type-defs.h20
-rw-r--r--source/slang/slang.cpp24
13 files changed, 387 insertions, 96 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index ad3f506a6..5054b00bc 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -234,9 +234,10 @@ namespace Slang
/// Is `decl` a global shader parameter declaration?
bool isGlobalShaderParameter(VarDeclBase* decl)
{
- // A global shader parameter must be declared at global (module) scope.
+ // A global shader parameter must be declared at global or namespace
+ // scope, so that it has a single definition across the module.
//
- if(!as<ModuleDecl>(decl->ParentDecl)) return false;
+ if(!as<NamespaceDeclBase>(decl->ParentDecl)) return false;
// A global variable marked `static` indicates a traditional
// global variable (albeit one that is implicitly local to
@@ -408,6 +409,11 @@ namespace Slang
auto type = GetSup(constraintDeclRef);
return QualType(type);
}
+ else if( auto namespaceDeclRef = declRef.as<NamespaceDeclBase>())
+ {
+ auto type = getNamespaceType(session, namespaceDeclRef);
+ return QualType(type);
+ }
if( sink )
{
// The compiler is trying to form a reference to a declaration
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index fbe38bac7..a8114c8d6 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -1423,7 +1423,37 @@ namespace Slang
{
auto& baseType = baseExpression->type;
- if (auto typeType = as<TypeType>(baseType))
+ // TODO: Need to handle overloaded case (in case we
+ // have multiple visible types and/or namespaces
+ // with the same name).
+
+ if (auto namespaceType = as<NamespaceType>(baseType))
+ {
+ // We are looking up a namespace member.
+ //
+ auto namespaceDeclRef = namespaceType->getDeclRef();
+
+ // This ought to be the easy case, because
+ // there are no restrictions on whether
+ // we can reference the declaration here.
+ //
+ LookupResult lookupResult = lookUpDirectAndTransparentMembers(
+ getSession(),
+ this,
+ expr->name,
+ namespaceDeclRef);
+ if (!lookupResult.isValid())
+ {
+ return lookupMemberResultFailure(expr, baseType);
+ }
+
+ return createLookupResultExpr(
+ expr->name,
+ lookupResult,
+ nullptr,
+ expr->loc);
+ }
+ else if (auto typeType = as<TypeType>(baseType))
{
// We are looking up a member inside a type.
// We want to be careful here because we should only find members
@@ -1594,6 +1624,11 @@ namespace Slang
//
expr->BaseExpression = maybeOpenExistential(expr->BaseExpression);
+ // TODO: Handle the case of an overloaded base expression
+ // here, in case we can use the name of the member to
+ // disambiguate which of the candidates is meant, or if
+ // we can return an overloaded result.
+
auto & baseType = expr->BaseExpression->type;
// Note: Checking for vector types before declaration-reference types,
@@ -1619,6 +1654,10 @@ namespace Slang
baseScalarType,
1);
}
+ else if( as<NamespaceType>(baseType) )
+ {
+ return _lookupStaticMember(expr, expr->BaseExpression);
+ }
else if(auto typeType = as<TypeType>(baseType))
{
return _lookupStaticMember(expr, expr->BaseExpression);
diff --git a/source/slang/slang-check-shader.cpp b/source/slang/slang-check-shader.cpp
index da0313049..53c3f8d89 100644
--- a/source/slang/slang-check-shader.cpp
+++ b/source/slang/slang-check-shader.cpp
@@ -1270,6 +1270,36 @@ namespace Slang
sink);
}
+ RefPtr<Scope> ComponentType::_createScopeForLegacyLookup()
+ {
+ // The shape of this logic is dictated by the legacy
+ // behavior for name-based lookup/parsing of types
+ // specified via the API or command line.
+ //
+ // We begin with a dummy scope that has as its parent
+ // the scope that provides the "base" langauge
+ // definitions (that scope is necessary because
+ // it defines keywords like `true` and `false`).
+ //
+ RefPtr<Scope> scope = new Scope();
+ scope->parent = getLinkage()->getSessionImpl()->baseLanguageScope;
+ //
+ // Next, the scope needs to include all of the
+ // modules in the program as peers, as if they
+ // were `import`ed into the scope.
+ //
+ for( auto module : getModuleDependencies() )
+ {
+ RefPtr<Scope> moduleScope = new Scope();
+ moduleScope->containerDecl = module->getModuleDecl();
+
+ moduleScope->nextSibling = scope->nextSibling;
+ scope->nextSibling = moduleScope;
+ }
+
+ return scope;
+ }
+
/// Parse an array of strings as specialization arguments.
///
/// Names in the strings will be parsed in the context of
@@ -1282,14 +1312,8 @@ namespace Slang
{
auto unspecialiedProgram = endToEndReq->getUnspecializedGlobalComponentType();
- // TODO: Building a list of `scopesToTry` here shouldn't
- // be required, since the `Scope` type itself has the ability
- // for form chains for lookup purposes (e.g., the way that
- // `import` is handled by modifying a scope).
- //
- List<RefPtr<Scope>> scopesToTry;
- for( auto module : unspecialiedProgram->getModuleDependencies() )
- scopesToTry.add(module->getModuleDecl()->scope);
+
+ RefPtr<Scope> scope = unspecialiedProgram->_createScopeForLegacyLookup();
// We are going to do some semantic checking, so we need to
// set up a `SemanticsVistitor` that we can use.
@@ -1311,16 +1335,8 @@ namespace Slang
//
for(auto name : genericArgStrings)
{
- RefPtr<Expr> argExpr;
- for (auto & s : scopesToTry)
- {
- argExpr = linkage->parseTermString(name, s);
- argExpr = semantics.CheckTerm(argExpr);
- if( argExpr )
- {
- break;
- }
- }
+ RefPtr<Expr> argExpr = linkage->parseTermString(name, scope);
+ argExpr = semantics.CheckTerm(argExpr);
if(!argExpr)
{
@@ -1606,6 +1622,14 @@ namespace Slang
outSpecializedEntryPoints.add(specializedEntryPoint);
}
+ // There might have been errors during the specialization above,
+ // so we will bail out early if anything went wrong, rather
+ // then try to create a composite where some of the constituent
+ // component types might be null.
+ //
+ if(endToEndReq->getSink()->GetErrorCount() != 0)
+ return nullptr;
+
// Any entry points beyond those that were specified up front will be
// assumed to not need/want specialization.
//
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 7cfc4fac1..89da498ac 100644
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -461,6 +461,13 @@ namespace Slang
///
virtual void acceptVisitor(ComponentTypeVisitor* visitor, SpecializationInfo* specializationInfo) = 0;
+ /// Create a scope suitable for looking up names or parsing specialization arguments.
+ ///
+ /// This facility is only needed to support legacy APIs for string-based lookup
+ /// and parsing via Slang reflection, and is not recommended for future APIs to use.
+ ///
+ RefPtr<Scope> _createScopeForLegacyLookup();
+
protected:
ComponentType(Linkage* linkage);
diff --git a/source/slang/slang-decl-defs.h b/source/slang/slang-decl-defs.h
index 0e3159910..b4c3bcfd4 100644
--- a/source/slang/slang-decl-defs.h
+++ b/source/slang/slang-decl-defs.h
@@ -241,11 +241,21 @@ SIMPLE_SYNTAX_CLASS(RefAccessorDecl, AccessorDecl)
SIMPLE_SYNTAX_CLASS(FuncDecl, FunctionDeclBase)
-// A "module" of code (essentiately, a single translation unit)
-// that provides a scope for some number of declarations.
-SYNTAX_CLASS(ModuleDecl, ContainerDecl)
- FIELD(RefPtr<Scope>, scope)
+SIMPLE_SYNTAX_CLASS(NamespaceDeclBase, ContainerDecl)
+
+ // A `namespace` declaration inside some module, that provides
+ // a named scope for declarations inside it.
+ //
+ // Note: Multiple `namespace` declarations with the same name
+ // in a given module/file will be collapsed into a single
+ // `NamespaceDecl` during parsing, so this declaration does
+ // not directly represent what is present in the input syntax.
+ //
+SIMPLE_SYNTAX_CLASS(NamespaceDecl, NamespaceDeclBase)
+ // A "module" of code (essentiately, a single translation unit)
+ // that provides a scope for some number of declarations.
+SYNTAX_CLASS(ModuleDecl, NamespaceDeclBase)
// The API-level module that this declaration belong to.
//
// This field allows lookup of the `Module` based on a
diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp
index 02f74579c..6a2d31c32 100644
--- a/source/slang/slang-lookup.cpp
+++ b/source/slang/slang-lookup.cpp
@@ -234,6 +234,29 @@ static void _lookUpDirectAndTransparentMembers(
}
}
+ /// Perform "direct" lookup in a container declaration
+LookupResult lookUpDirectAndTransparentMembers(
+ Session* session,
+ SemanticsVisitor* semantics,
+ Name* name,
+ DeclRef<ContainerDecl> containerDeclRef,
+ LookupMask mask)
+{
+ LookupRequest request;
+ request.semantics = semantics;
+ request.mask = mask;
+ LookupResult result;
+ _lookUpDirectAndTransparentMembers(
+ session,
+ name,
+ containerDeclRef,
+ request,
+ result,
+ nullptr);
+ return result;
+}
+
+
static RefPtr<SubtypeWitness> _makeSubtypeWitness(
Type* subType,
SubtypeWitness* subToMidWitness,
@@ -607,6 +630,12 @@ static void _lookUpInScopes(
{
auto containerDecl = link->containerDecl;
+ // It is possible for the first scope in a list of
+ // siblings to be a "dummy" scope that only exists
+ // to combine the siblings; in that case it will
+ // have a null `containerDecl` and needs to be
+ // skipped over.
+ //
if(!containerDecl)
continue;
diff --git a/source/slang/slang-lookup.h b/source/slang/slang-lookup.h
index f9e3839d9..0f44121c6 100644
--- a/source/slang/slang-lookup.h
+++ b/source/slang/slang-lookup.h
@@ -32,6 +32,14 @@ LookupResult lookUpMember(
Type* type,
LookupMask mask = LookupMask::Default);
+ /// Perform "direct" lookup in a container declaration
+LookupResult lookUpDirectAndTransparentMembers(
+ Session* session,
+ SemanticsVisitor* semantics,
+ Name* name,
+ DeclRef<ContainerDecl> containerDeclRef,
+ LookupMask mask = LookupMask::Default);
+
// TODO: this belongs somewhere else
QualType getTypeForDeclRef(
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index ea1196a6c..a52f67b8a 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -1575,6 +1575,8 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
UNEXPECTED_CASE(ErrorType)
UNEXPECTED_CASE(InitializerListType)
UNEXPECTED_CASE(OverloadGroupType)
+ UNEXPECTED_CASE(NamespaceType)
+#undef UNEXPECTED_CASE
};
LoweredValInfo lowerVal(
@@ -4256,25 +4258,16 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
return LoweredValInfo();
}
- LoweredValInfo visitImportDecl(ImportDecl* /*decl*/)
- {
- return LoweredValInfo();
- }
+#define IGNORED_CASE(NAME) \
+ LoweredValInfo visit##NAME(NAME*) { return LoweredValInfo(); }
- LoweredValInfo visitEmptyDecl(EmptyDecl* /*decl*/)
- {
- return LoweredValInfo();
- }
+ IGNORED_CASE(ImportDecl)
+ IGNORED_CASE(EmptyDecl)
+ IGNORED_CASE(SyntaxDecl)
+ IGNORED_CASE(AttributeDecl)
+ IGNORED_CASE(NamespaceDecl)
- LoweredValInfo visitSyntaxDecl(SyntaxDecl* /*decl*/)
- {
- return LoweredValInfo();
- }
-
- LoweredValInfo visitAttributeDecl(AttributeDecl* /*decl*/)
- {
- return LoweredValInfo();
- }
+#undef IGNORED_CASE
LoweredValInfo visitTypeDefDecl(TypeDefDecl* decl)
{
@@ -4575,9 +4568,9 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
bool isGlobalVarDecl(VarDecl* decl)
{
auto parent = decl->ParentDecl;
- if (as<ModuleDecl>(parent))
+ if (as<NamespaceDeclBase>(parent))
{
- // Variable declared at global scope? -> Global.
+ // Variable declared at global/namespace scope? -> Global.
return true;
}
else if(as<AggTypeDeclBase>(parent))
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 5a99f6ffb..03f53634d 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -180,17 +180,18 @@ namespace Slang
// Forward Declarations
- static void ParseDeclBody(
- Parser* parser,
- ContainerDecl* containerDecl,
- TokenType closingToken);
+ /// Parse declarations making up the body of `parent`, up to the matching `closingToken`
+ static void parseDecls(
+ Parser* parser,
+ ContainerDecl* parent,
+ TokenType closingToken);
- static RefPtr<Decl> parseEnumDecl(Parser* parser);
+ /// Parse a body consisting of declarations enclosed in `{}`, as the children of `parent`.
+ static void parseDeclBody(
+ Parser* parser,
+ ContainerDecl* parent);
- // Parse the `{}`-delimeted body of an aggregate type declaration
- static void parseAggTypeDeclBody(
- Parser* parser,
- AggTypeDeclBase* decl);
+ static RefPtr<Decl> parseEnumDecl(Parser* parser);
static RefPtr<Modifier> ParseOptSemantics(
Parser* parser);
@@ -2342,7 +2343,7 @@ namespace Slang
ParseOptSemantics(parser, bufferVarDecl.Ptr());
// The declarations in the body belong to the data type.
- parseAggTypeDeclBody(parser, bufferDataTypeDecl.Ptr());
+ parseDeclBody(parser, bufferDataTypeDecl.Ptr());
// All HLSL buffer declarations are "transparent" in that their
// members are implicitly made visible in the parent scope.
@@ -2403,7 +2404,7 @@ namespace Slang
parser->FillPosition(decl.Ptr());
decl->targetType = parser->ParseTypeExp();
parseOptionalInheritanceClause(parser, decl);
- parseAggTypeDeclBody(parser, decl.Ptr());
+ parseDeclBody(parser, decl.Ptr());
return decl;
}
@@ -2488,11 +2489,130 @@ namespace Slang
parseOptionalInheritanceClause(parser, decl.Ptr());
- parseAggTypeDeclBody(parser, decl.Ptr());
+ parseDeclBody(parser, decl.Ptr());
return decl;
}
+ static RefPtr<RefObject> parseNamespaceDecl(Parser* parser, void* /*userData*/)
+ {
+ // We start by parsing the name of the namespace that is being opened.
+ //
+ // TODO: We should eventually support a qualified name for
+ // a namespace declaration:
+ //
+ // namespace A.B { ... }
+ //
+ // which should expand as if the user had written nested
+ // namespace declarations:
+ //
+ // namespace A { namespace B { ... } }
+ //
+ // TODO: Support we also support the degenerate case of
+ // a namesapce without a name? Should that be treated as
+ // an anonymous (and implicitly imported) namespace, or
+ // something else?
+ //
+ // TODO: Should we support a shorthand syntax for putting
+ // the rest of the current scope/file into a namespace:
+ //
+ // namespace A.B;
+ //
+ // ...
+ //
+ NameLoc nameAndLoc = NameLoc(parser->ReadToken(TokenType::Identifier));
+
+ // Once we have the name for the namespace, we face a challenge:
+ // either the namespace hasn't been seen before (in which case
+ // we need to create it and start filling it in), or we've seen
+ // the same namespace before inside the same module, such that
+ // we should be adding the declarations we parse to the existing
+ // declarations (so that they share a common scope/parent).
+ //
+ // In each case we will find a namespace that we want to fill in,
+ // but depending on the case we may or may not want to return
+ // a declaration to the caller (since they will try to add
+ // any non-null pointer we return to the AST).
+ //
+ RefPtr<NamespaceDecl> namespaceDecl;
+ RefPtr<RefObject> result;
+ //
+ // In order to find out what case we are in, we start by looking
+ // for a namespace declaration of the same name in the parent
+ // declaration.
+ //
+ {
+ auto parentDecl = parser->currentScope->containerDecl;
+ SLANG_ASSERT(parentDecl);
+
+ // We meed to make sure that the member dictionary of
+ // the parent declaration has been built/rebuilt so that
+ // lookup by name will work.
+ //
+ // TODO: The current way we rebuild the member dictionary
+ // would make for O(N^2) parsing time in a file that
+ // consisted of N back-to-back `namespace`s, since each
+ // would trigger a rebuild of the member dictionary that
+ // would take O(N) time.
+ //
+ // Eventually we should make `builtMemberDictionary()`
+ // incremental, so that it only has to process members
+ // added since the last time it was invoked.
+ //
+ buildMemberDictionary(parentDecl);
+
+ // There might be multiple members of the same name
+ // (if we define a namespace `foo` after an overloaded
+ // function `foo` has been defined), and direct member
+ // lookup will only give us the first.
+ //
+ Decl* firstDecl = nullptr;
+ parentDecl->memberDictionary.TryGetValue(nameAndLoc.name, firstDecl);
+ //
+ // We will search through the declarations of the name
+ // and find the first that is a namespace (if any).
+ //
+ // Note: we do not issue diagnostics here based on
+ // the potential conflicts between these declarations,
+ // because we want to do as little semantic analysis
+ // as possible in the parser, and we'd rather be
+ // as permissive as possible right now.
+ //
+ for(Decl* d = firstDecl; d; d = d->nextInContainerWithSameName)
+ {
+ namespaceDecl = as<NamespaceDecl>(d);
+ if(namespaceDecl)
+ break;
+ }
+
+ // If we didn't find a pre-existing namespace, then
+ // we will go ahead and create one now.
+ //
+ if( !namespaceDecl )
+ {
+ namespaceDecl = new NamespaceDecl();
+ namespaceDecl->nameAndLoc = nameAndLoc;
+
+ // In the case where we are creating the first
+ // declaration of the given namesapce, we need
+ // to use it as the return value of the parsing
+ // callback, so that it is appropriately added
+ // to the parent declaration.
+ //
+ result = namespaceDecl;
+ }
+ }
+
+ // Now that we have a namespace declaration to fill in
+ // (whether a new or existing one), we can parse the
+ // `{}`-enclosed body to add declarations as children
+ // of the namespace.
+ //
+ parseDeclBody(parser, namespaceDecl.Ptr());
+
+ return result;
+ }
+
static RefPtr<RefObject> parseConstructorDecl(Parser* parser, void* /*userData*/)
{
RefPtr<ConstructorDecl> decl = new ConstructorDecl();
@@ -3040,8 +3160,7 @@ namespace Slang
}
- // Parse a body consisting of declarations
- static void ParseDeclBody(
+ static void parseDecls(
Parser* parser,
ContainerDecl* containerDecl,
TokenType closingToken)
@@ -3052,22 +3171,14 @@ namespace Slang
}
}
- // Parse the `{}`-delimeted body of an aggregate type declaration
- static void parseAggTypeDeclBody(
- Parser* parser,
- AggTypeDeclBase* decl)
+ static void parseDeclBody(
+ Parser* parser,
+ ContainerDecl* parent)
{
- // TODO: the scope used for the body might need to be
- // slightly specialized to deal with the complexity
- // of how `this` works.
- //
- // Alternatively, that complexity can be pushed down
- // to semantic analysis so that it doesn't clutter
- // things here.
- parser->PushScope(decl);
+ parser->PushScope(parent);
parser->ReadToken(TokenType::LBrace);
- ParseDeclBody(parser, decl, TokenType::RBrace);
+ parseDecls(parser, parent, TokenType::RBrace);
parser->PopScope();
}
@@ -3081,9 +3192,25 @@ namespace Slang
}
PushScope(program);
- program->loc = tokenReader.peekLoc();
- program->scope = currentScope;
- ParseDeclBody(this, program, TokenType::EndOfFile);
+
+ // A single `ModuleDecl` might span multiple source files, so it
+ // is possible that we are parsing a new source file into a module
+ // that has already been created and filled in for a previous
+ // source file.
+ //
+ // If this is the first source file for the module then we expect
+ // its location information to be invalid, and we will set it to
+ // refer to the start of the first source file.
+ //
+ // This convention is reasonable for any single-source-file module,
+ // and about as good as possible for multiple-file modules.
+ //
+ if(!program->loc.isValid())
+ {
+ program->loc = tokenReader.peekLoc();
+ }
+
+ parseDecls(this, program, TokenType::EndOfFile);
PopScope();
SLANG_RELEASE_ASSERT(currentScope == outerScope);
@@ -3104,7 +3231,7 @@ namespace Slang
// We allow for an inheritance clause on a `struct`
// so that it can conform to interfaces.
parseOptionalInheritanceClause(this, rs.Ptr());
- parseAggTypeDeclBody(this, rs.Ptr());
+ parseDeclBody(this, rs.Ptr());
return rs;
});
}
@@ -3118,7 +3245,7 @@ namespace Slang
parseOptionalInheritanceClause(this, rs.Ptr());
- parseAggTypeDeclBody(this, rs.Ptr());
+ parseDeclBody(this, rs.Ptr());
return rs;
}
@@ -5097,6 +5224,7 @@ namespace Slang
DECL(func, parseFuncDecl);
DECL(typealias, parseTypeAliasDecl);
DECL(__generic_value_param, parseGlobalGenericValueParamDecl);
+ DECL(namespace, parseNamespaceDecl);
#undef DECL
diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp
index d479ba32a..1dcaafec5 100644
--- a/source/slang/slang-syntax.cpp
+++ b/source/slang/slang-syntax.cpp
@@ -1280,6 +1280,35 @@ void Type::accept(IValVisitor* visitor, void* extra)
return this;
}
+ // NamespaceType
+
+ String NamespaceType::ToString()
+ {
+ String result;
+ result.append("namespace ");
+ result.append(m_declRef.toString());
+ return result;
+ }
+
+ bool NamespaceType::EqualsImpl(Type * type)
+ {
+ if (auto namespaceType = as<NamespaceType>(type))
+ {
+ return m_declRef.Equals(namespaceType->m_declRef);
+ }
+ return false;
+ }
+
+ int NamespaceType::GetHashCode()
+ {
+ return m_declRef.GetHashCode();
+ }
+
+ RefPtr<Type> NamespaceType::CreateCanonicalType()
+ {
+ return this;
+ }
+
// ArithmeticExpressionType
// VectorExpressionType
@@ -2301,6 +2330,16 @@ void Type::accept(IValVisitor* visitor, void* extra)
return genericDeclRefType;
}
+ RefPtr<NamespaceType> getNamespaceType(
+ Session* session,
+ DeclRef<NamespaceDeclBase> const& declRef)
+ {
+ auto type = new NamespaceType;
+ type->setSession(session);
+ type->m_declRef = declRef;
+ return type;
+ }
+
RefPtr<SamplerStateType> getSamplerStateType(
Session* session)
{
diff --git a/source/slang/slang-syntax.h b/source/slang/slang-syntax.h
index 61219ecd2..061ca4d26 100644
--- a/source/slang/slang-syntax.h
+++ b/source/slang/slang-syntax.h
@@ -1526,6 +1526,10 @@ namespace Slang
Session* session,
DeclRef<GenericDecl> const& declRef);
+ RefPtr<NamespaceType> getNamespaceType(
+ Session* session,
+ DeclRef<NamespaceDeclBase> const& declRef);
+
RefPtr<SamplerStateType> getSamplerStateType(
Session* session);
diff --git a/source/slang/slang-type-defs.h b/source/slang/slang-type-defs.h
index 9b28681d5..356aa05d2 100644
--- a/source/slang/slang-type-defs.h
+++ b/source/slang/slang-type-defs.h
@@ -444,6 +444,25 @@ protected:
)
END_SYNTAX_CLASS()
+// The "type" of a reference to a module or namespace
+SYNTAX_CLASS(NamespaceType, Type)
+ DECL_FIELD(DeclRef<NamespaceDeclBase>, m_declRef)
+
+RAW(
+ NamespaceType()
+ {}
+
+ DeclRef<NamespaceDeclBase> const& getDeclRef() const { return m_declRef; }
+
+ virtual String ToString() override;
+
+protected:
+ virtual bool EqualsImpl(Type * type) override;
+ virtual int GetHashCode() override;
+ virtual RefPtr<Type> CreateCanonicalType() override;
+)
+END_SYNTAX_CLASS()
+
// The concrete type for a value wrapped in an existential, accessible
// when the existential is "opened" in some context.
SYNTAX_CLASS(ExtractExistentialType, Type)
@@ -501,4 +520,3 @@ RAW(
virtual RefPtr<Val> SubstituteImpl(SubstitutionSet subst, int* ioDiff) override;
)
END_SYNTAX_CLASS()
-
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 6c1a59ea4..aefe70a4a 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -890,24 +890,13 @@ Type* ComponentType::getTypeFromString(
// the modules that were directly or
// indirectly referenced.
//
- // TODO: This `scopesToTry` idiom appears
- // all over the code, and isn't really
- // how we should be handling this kind of
- // lookup at all.
- //
- List<RefPtr<Scope>> scopesToTry;
- for(auto module : getModuleDependencies())
- scopesToTry.add(module->getModuleDecl()->scope);
+ RefPtr<Scope> scope = _createScopeForLegacyLookup();
auto linkage = getLinkage();
- for(auto& s : scopesToTry)
- {
- RefPtr<Expr> typeExpr = linkage->parseTermString(
- typeStr, s);
- type = checkProperType(linkage, TypeExp(typeExpr), sink);
- if (type && !type.as<ErrorType>())
- break;
- }
+ RefPtr<Expr> typeExpr = linkage->parseTermString(
+ typeStr, scope);
+ type = checkProperType(linkage, TypeExp(typeExpr), sink);
+
if( type )
{
m_types[typeStr] = type;
@@ -915,9 +904,6 @@ Type* ComponentType::getTypeFromString(
return type;
}
-
-
-
CompileRequestBase::CompileRequestBase(
Linkage* linkage,
DiagnosticSink* sink)