From 6e591ada0eb652c320bba4bd8a46cd579946df01 Mon Sep 17 00:00:00 2001 From: Yong He Date: Tue, 7 Nov 2017 19:09:40 -0500 Subject: Support generic interface methods (#251) * improve diagnostic messages and prevent fatal errors from crashing the compiler. * fix top level exception catching. * spelling fix * change wording of invalidSwizzleExpr diagnostic * add speculative GenericsApp expr parsing * add new test case of cascading generics call. * Fixing bugs in compiling cascaded generic function calls. Add implementation of DeclaredSubTypeWitness::SubstituteImpl() This is not needed by the type checker, but needed by IR specialization. When input source contains cascading generic function call, the arguments to `specialize` instruction is currently represented as a substitution. The arg values of this subsittution can be a `DeclaredSubTypeWitness` when a generic function uses one of its generic parameter to specialize another generic function. When the top level generics function is being specialized, this substitution argument, which is a `DeclaredSubTypeWitness`, needs to be substituted with the witness that used to specialize the top level function in the specialized specialize instruction as well. * add a test case for cascading generic function call. * parser bug fix * fixes #255 * add test case for issue #255 * Generate missing `specialize` instruction when calling a generic method from an interface constraint. When calling a generic method via an interface, we should be generating the following ir: ... f = lookup_interface_method(...) f_s = specailize(f, declRef) ... This commit fixes this `emitFuncRef` function to emit the needed `specialize` instruction. * fixes #260 This fix follows the second apporach in the disucssion. It generated mangled name for specialized functions by appending new substitution type names to the original mangled name. * Disabling removing and re-inserting specailized functions in getSpecalizeFunc() I am not sure why it is needed, it seems HLSL and GLSL backends are generating forward declarations anyways, so the order of functions in IRModule shouldn't matter. * cleanup and complete test cases. * fix warnings --- source/slang/parser.cpp | 104 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 71 insertions(+), 33 deletions(-) (limited to 'source/slang/parser.cpp') diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index 595d58d7e..eb02d98c5 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -77,7 +77,7 @@ namespace Slang , sink(sink) , outerScope(outerScope) {} - + Parser(const Parser & other) = default; Session* getSession() { return translationUnit->compileRequest->mSession; @@ -1396,6 +1396,69 @@ namespace Slang return genericApp; } + static bool isGenericName(Parser* parser, Name* name) + { + auto lookupResult = lookUp( + parser->getSession(), + nullptr, // no semantics visitor available yet + name, + parser->currentScope); + if (!lookupResult.isValid() || lookupResult.isOverloaded()) + return false; + + auto decl = lookupResult.item.declRef.getDecl(); + if (auto genericDecl = dynamic_cast(decl)) + { + return true; + } + else + { + return false; + } + } + + static RefPtr tryParseGenericApp( + Parser* parser, + RefPtr base) + { + Name * baseName = nullptr; + if (auto varExpr = base->As()) + baseName = varExpr->name; + // if base is a known generics, parse as generics + if (baseName && isGenericName(parser, baseName)) + return parseGenericApp(parser, base); + + // otherwise, we speculate as generics, and fallback to comparison when parsing failed + TokenSpan tokenSpan; + tokenSpan.mBegin = parser->tokenReader.mCursor; + tokenSpan.mEnd = parser->tokenReader.mEnd; + DiagnosticSink newSink; + newSink.sourceManager = parser->sink->sourceManager; + Parser newParser(*parser); + newParser.sink = &newSink; + auto speculateParseRs = parseGenericApp(&newParser, base); + if (newSink.errorCount == 0) + { + // disambiguate based on FOLLOW set + switch (peekTokenType(&newParser)) + { + case TokenType::Dot: + case TokenType::LParent: + case TokenType::RParent: + case TokenType::RBracket: + case TokenType::Colon: + case TokenType::Comma: + case TokenType::QuestionMark: + case TokenType::Semicolon: + case TokenType::OpEql: + case TokenType::OpNeq: + { + return parseGenericApp(parser, base); + } + } + } + return base; + } static RefPtr parseMemberType(Parser * parser, RefPtr base) { RefPtr memberExpr = new MemberExpr(); @@ -2624,28 +2687,6 @@ namespace Slang return stmt; } - static bool isGenericName(Parser* parser, Name* name) - { - auto lookupResult = lookUp( - parser->getSession(), - nullptr, // no semantics visitor available yet - name, - parser->currentScope); - if(!lookupResult.isValid() || lookupResult.isOverloaded()) - return false; - - auto decl = lookupResult.item.declRef.getDecl(); - if( auto genericDecl = dynamic_cast(decl) ) - { - return true; - } - else - { - return false; - } - } - - static bool isTypeName(Parser* parser, Name* name) { auto lookupResult = lookUp( @@ -3367,24 +3408,18 @@ namespace Slang } #endif } - + // We *might* be looking at an application of a generic to arguments, // but we need to disambiguate to make sure. static RefPtr maybeParseGenericApp( Parser* parser, // TODO: need to support more general expressions here - RefPtr base) + RefPtr base) { if(peekTokenType(parser) != TokenType::OpLess) return base; - - if(!isGenericName(parser, base->name)) - return base; - - // Okay, seems likely that we are looking at a generic app - - return parseGenericApp(parser, base); + return tryParseGenericApp(parser, base); } static RefPtr parsePrefixExpr(Parser* parser); @@ -3769,7 +3804,10 @@ namespace Slang parser->ReadToken(TokenType::Dot); memberExpr->name = expectIdentifier(parser).name; - expr = memberExpr; + if (peekTokenType(parser) == TokenType::OpLess) + expr = maybeParseGenericApp(parser, memberExpr); + else + expr = memberExpr; } break; } -- cgit v1.2.3