diff options
| author | Tim Foley <tfoleyNV@users.noreply.github.com> | 2020-04-02 08:52:42 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-02 08:52:42 -0700 |
| commit | 487d4a4f406c9dd9803ecdca02467d09ee1ecf4a (patch) | |
| tree | c1a64a26620de90636f16fa0fdb117f3a3c4f92e /source/slang | |
| parent | 5e73e984022c9ec8e901ccffc94d3cd5f374642a (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.cpp | 10 | ||||
| -rw-r--r-- | source/slang/slang-check-expr.cpp | 41 | ||||
| -rw-r--r-- | source/slang/slang-check-shader.cpp | 60 | ||||
| -rw-r--r-- | source/slang/slang-compiler.h | 7 | ||||
| -rw-r--r-- | source/slang/slang-decl-defs.h | 18 | ||||
| -rw-r--r-- | source/slang/slang-lookup.cpp | 29 | ||||
| -rw-r--r-- | source/slang/slang-lookup.h | 8 | ||||
| -rw-r--r-- | source/slang/slang-lower-to-ir.cpp | 31 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 192 | ||||
| -rw-r--r-- | source/slang/slang-syntax.cpp | 39 | ||||
| -rw-r--r-- | source/slang/slang-syntax.h | 4 | ||||
| -rw-r--r-- | source/slang/slang-type-defs.h | 20 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 24 |
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) |
