summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang-ast-base.h2
-rw-r--r--source/slang/slang-ast-dump.cpp2
-rw-r--r--source/slang/slang-ast-stmt.h4
-rw-r--r--source/slang/slang-ast-support-types.h4
-rw-r--r--source/slang/slang-check-conversion.cpp3
-rw-r--r--source/slang/slang-check-decl.cpp28
-rw-r--r--source/slang/slang-check-expr.cpp6
-rw-r--r--source/slang/slang-check-impl.h12
-rw-r--r--source/slang/slang-check-stmt.cpp31
-rw-r--r--source/slang/slang-diagnostic-defs.h5
-rw-r--r--source/slang/slang-language-server-document-symbols.cpp5
-rw-r--r--source/slang/slang-lookup.cpp4
-rw-r--r--source/slang/slang-parser.cpp238
-rw-r--r--source/slang/slang-parser.h13
14 files changed, 327 insertions, 30 deletions
diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h
index 8c2f7afa7..9cc36e530 100644
--- a/source/slang/slang-ast-base.h
+++ b/source/slang/slang-ast-base.h
@@ -791,6 +791,8 @@ public:
// Track the decl reference that caused the requirement of a capability atom.
SLANG_UNREFLECTED List<DeclReferenceWithLoc> capabilityRequirementProvenance;
+ SLANG_UNREFLECTED bool hiddenFromLookup = false;
+
private:
SLANG_UNREFLECTED DeclRefBase* m_defaultDeclRef = nullptr;
};
diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp
index 85d2d0d9f..f6cdf50d8 100644
--- a/source/slang/slang-ast-dump.cpp
+++ b/source/slang/slang-ast-dump.cpp
@@ -645,6 +645,8 @@ struct ASTDumpContext
m_writer->emit(info->m_name);
}
+ void dump(SourceLanguage language) { m_writer->emit((int)language); }
+
void dump(KeyValuePair<DeclRefBase*, SubtypeWitness*> pair)
{
m_writer->emit("(");
diff --git a/source/slang/slang-ast-stmt.h b/source/slang/slang-ast-stmt.h
index 8c21f78a5..eba7027c2 100644
--- a/source/slang/slang-ast-stmt.h
+++ b/source/slang/slang-ast-stmt.h
@@ -52,6 +52,10 @@ class UnparsedStmt : public Stmt
// The tokens that were contained between `{` and `}`
List<Token> tokens;
+ Scope* currentScope = nullptr;
+ Scope* outerScope = nullptr;
+ SourceLanguage sourceLanguage;
+ bool isInVariadicGenerics = false;
};
class EmptyStmt : public Stmt
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index 2581630dd..72707ab38 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -419,6 +419,10 @@ enum class DeclCheckState : uint8_t
///
Unchecked,
+ /// The declaration is parsed and inserted into the initial scope,
+ /// ready for future lookups from within the parser for disambiguation purposes.
+ ReadyForParserLookup,
+
/// Basic checks on the modifiers of the declaration have been applied.
///
/// For example, when a declaration has attributes, the transformation
diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp
index d89997bad..6bbdc1477 100644
--- a/source/slang/slang-check-conversion.cpp
+++ b/source/slang/slang-check-conversion.cpp
@@ -1254,6 +1254,7 @@ bool SemanticsVisitor::_coerce(
auto resultExpr = getASTBuilder()->create<MakeOptionalExpr>();
resultExpr->loc = fromExpr->loc;
resultExpr->type = toType;
+ resultExpr->checked = true;
*outToExpr = resultExpr;
}
return true;
@@ -1379,6 +1380,7 @@ bool SemanticsVisitor::_coerce(
derefExpr = m_astBuilder->create<DerefExpr>();
derefExpr->base = fromExpr;
derefExpr->type = QualType(fromElementType);
+ derefExpr->checked = true;
}
if (!_coerce(site, toType, outToExpr, fromElementType, derefExpr, &subCost))
@@ -1407,6 +1409,7 @@ bool SemanticsVisitor::_coerce(
refExpr->base = fromExpr;
refExpr->type = QualType(refType);
refExpr->type.isLeftValue = false;
+ refExpr->checked = true;
*outToExpr = refExpr;
}
if (outCost)
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index b03126512..ab3335bfb 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -16,6 +16,7 @@
#include "slang-ast-reflect.h"
#include "slang-ast-synthesis.h"
#include "slang-lookup.h"
+#include "slang-parser.h"
#include "slang-syntax.h"
#include <limits>
@@ -4558,6 +4559,7 @@ void SemanticsVisitor::addRequiredParamsToSynthesizedDecl(
synMemberExpr->elementIndices.add((uint32_t)i);
synMemberExpr->type = elementType;
synMemberExpr->type.isLeftValue = paramType.isLeftValue;
+ synMemberExpr->checked = true;
synArgs.add(synMemberExpr);
}
}
@@ -8165,6 +8167,7 @@ SemanticsContext SemanticsDeclBodyVisitor::registerDifferentiableTypesForFunc(
void SemanticsDeclBodyVisitor::visitFunctionDeclBase(FunctionDeclBase* decl)
{
auto newContext = registerDifferentiableTypesForFunc(decl);
+ decl->body = maybeParseStmt(decl->body, newContext);
if (const auto body = decl->body)
{
checkStmt(decl->body, newContext);
@@ -9472,6 +9475,28 @@ void SemanticsDeclBodyVisitor::visitAggTypeDecl(AggTypeDecl* aggTypeDecl)
}
}
+Stmt* SemanticsVisitor::maybeParseStmt(Stmt* stmt, const SemanticsContext& context)
+{
+ if (auto unparsedStmt = as<UnparsedStmt>(stmt))
+ {
+ // Parse the statement now, and check it.
+ SemanticsVisitor subVisitor(context);
+ TokenList tokenList;
+ tokenList.m_tokens = _Move(unparsedStmt->tokens);
+ return parseUnparsedStmt(
+ m_astBuilder,
+ &subVisitor,
+ getShared()->getTranslationUnitRequest(),
+ unparsedStmt->sourceLanguage,
+ unparsedStmt->isInVariadicGenerics,
+ tokenList,
+ getShared()->getSink(),
+ unparsedStmt->currentScope,
+ unparsedStmt->outerScope);
+ }
+ return stmt;
+}
+
void SemanticsDeclHeaderVisitor::cloneModifiers(Decl* dest, Decl* src)
{
dest->modifiers = src->modifiers;
@@ -11182,6 +11207,9 @@ static void _dispatchDeclCheckingVisitor(Decl* decl, DeclCheckState state, Seman
{
switch (state)
{
+ case DeclCheckState::ReadyForParserLookup:
+ // We don't need to do anything to make a decl ready for parser lookup.
+ break;
case DeclCheckState::ModifiersChecked:
SemanticsDeclModifiersVisitor(shared).dispatch(decl);
break;
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index 7726fd6c8..7d4fbdf4c 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -167,7 +167,7 @@ Expr* SemanticsVisitor::openExistential(Expr* expr, DeclRef<InterfaceDecl> inter
openedValue->declRef = varDeclRef;
openedValue->type = QualType(openedType);
openedValue->originalExpr = expr;
-
+ openedValue->checked = true;
// The result of opening an existential is an l-value
// if the original existential is an l-value.
//
@@ -226,6 +226,7 @@ Expr* SemanticsVisitor::maybeOpenRef(Expr* expr)
openRef->innerExpr = expr;
openRef->type.isLeftValue = (as<RefType>(exprType) != nullptr);
openRef->type.type = refType->getValueType();
+ openRef->checked = true;
return openRef;
}
return expr;
@@ -522,6 +523,7 @@ Expr* SemanticsVisitor::constructDerefExpr(Expr* base, QualType elementType, Sou
derefExpr->loc = loc;
derefExpr->base = base;
derefExpr->type = QualType(elementType);
+ derefExpr->checked = true;
if (as<PtrType>(base->type) || as<RefType>(base->type))
{
@@ -3918,6 +3920,7 @@ Expr* SemanticsExprVisitor::visitAsTypeExpr(AsTypeExpr* expr)
makeOptional->type = optType;
makeOptional->value = castToSuperType;
makeOptional->typeExpr = typeExpr.exp;
+ makeOptional->checked = true;
return makeOptional;
}
@@ -4125,6 +4128,7 @@ Expr* SemanticsVisitor::CheckMatrixSwizzleExpr(
swizExpr->loc = memberRefExpr->loc;
swizExpr->base = memberRefExpr->baseExpression;
swizExpr->memberOpLoc = memberRefExpr->memberOperatorLoc;
+ swizExpr->checked = true;
// We can have up to 4 swizzles of two elements each
MatrixCoord elementCoords[4];
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 3276b7534..e6520cfd3 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -2035,6 +2035,8 @@ public:
void checkStmt(Stmt* stmt, SemanticsContext const& context);
+ Stmt* maybeParseStmt(Stmt* stmt, const SemanticsContext& context);
+
void getGenericParams(
GenericDecl* decl,
List<Decl*>& outParams,
@@ -2877,14 +2879,8 @@ public:
// deal with this cases here, even if they are no-ops.
//
-#define CASE(NAME) \
- Expr* visit##NAME(NAME* expr) \
- { \
- if (!getShared()->isInLanguageServer()) \
- SLANG_DIAGNOSE_UNEXPECTED(getSink(), expr, "should not appear in input syntax"); \
- expr->type = m_astBuilder->getErrorType(); \
- return expr; \
- }
+#define CASE(NAME) \
+ Expr* visit##NAME(NAME* expr) { return expr; }
CASE(DerefExpr)
CASE(MakeRefExpr)
diff --git a/source/slang/slang-check-stmt.cpp b/source/slang/slang-check-stmt.cpp
index 550993957..151c9324a 100644
--- a/source/slang/slang-check-stmt.cpp
+++ b/source/slang/slang-check-stmt.cpp
@@ -54,6 +54,8 @@ void SemanticsStmtVisitor::visitDeclStmt(DeclStmt* stmt)
// that need to be recursively checked.
//
ensureDeclBase(stmt->decl, DeclCheckState::DefinitionChecked, this);
+ if (auto decl = as<Decl>(stmt->decl))
+ decl->hiddenFromLookup = false;
}
void SemanticsStmtVisitor::visitBlockStmt(BlockStmt* stmt)
@@ -66,14 +68,41 @@ void SemanticsStmtVisitor::visitBlockStmt(BlockStmt* stmt)
if (as<AggTypeDeclBase>(decl))
ensureAllDeclsRec(decl, DeclCheckState::DefinitionChecked);
}
+
+ // Consider this code:
+ // ```
+ // {
+ // int a = 5 + b; // should error.
+ // int b = 3;
+ // }
+ //
+ // ```
+ // In order to detect the error trying to use `b` before it's declared within
+ // a block, our lookup logic contains a condition that ignores a decl if its
+ // `hiddenFromLookup` field is set to `true`.
+ // See _lookUpDirectAndTransparentMembers().
+ // This field will be set to false when we reach the decl through the DeclStmt.
+ //
+ if (auto seqStmt = as<SeqStmt>(stmt->body))
+ {
+ for (auto subStmt : seqStmt->stmts)
+ {
+ if (auto declStmt = as<DeclStmt>(subStmt))
+ {
+ if (auto decl = as<Decl>(declStmt->decl))
+ decl->hiddenFromLookup = true;
+ }
+ }
+ }
}
checkStmt(stmt->body);
}
void SemanticsStmtVisitor::visitSeqStmt(SeqStmt* stmt)
{
- for (auto ss : stmt->stmts)
+ for (auto& ss : stmt->stmts)
{
+ ss = maybeParseStmt(ss, *this);
checkStmt(ss);
}
}
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 682980107..4d037b68e 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -456,6 +456,11 @@ DIAGNOSTIC(
Error,
unexpectedTokenExpectedComponentDefinition,
"unexpected token '$0', only component definitions are allowed in a shader scope.")
+DIAGNOSTIC(
+ 20005,
+ Error,
+ invalidEmptyParenthesisExpr,
+ "empty parenthesis '()' is not a valid expression.")
DIAGNOSTIC(20008, Error, invalidOperator, "invalid operator '$0'.")
DIAGNOSTIC(20011, Error, unexpectedColon, "unexpected ':'.")
DIAGNOSTIC(
diff --git a/source/slang/slang-language-server-document-symbols.cpp b/source/slang/slang-language-server-document-symbols.cpp
index c13316a71..e8a041ca8 100644
--- a/source/slang/slang-language-server-document-symbols.cpp
+++ b/source/slang/slang-language-server-document-symbols.cpp
@@ -90,6 +90,11 @@ static SourceLoc _findClosingSourceLoc(Decl* decl)
{
return block->closingSourceLoc;
}
+ else if (auto unparsedStmt = as<UnparsedStmt>(func->body))
+ {
+ if (unparsedStmt->tokens.getCount())
+ return unparsedStmt->tokens.getLast().getLoc();
+ }
else if (func->body)
{
return func->body->loc;
diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp
index 72fbed581..9b9034c63 100644
--- a/source/slang/slang-lookup.cpp
+++ b/source/slang/slang-lookup.cpp
@@ -161,8 +161,8 @@ static void _lookUpMembersInValue(
static bool _isUncheckedLocalVar(const Decl* decl)
{
auto checkStateExt = decl->checkState;
- auto isUnchecked =
- checkStateExt.getState() == DeclCheckState::Unchecked || checkStateExt.isBeingChecked();
+ auto isUnchecked = checkStateExt.getState() == DeclCheckState::Unchecked ||
+ checkStateExt.isBeingChecked() || decl->hiddenFromLookup;
return isUnchecked && isLocalVar(decl);
}
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 0d7281e3f..342ac9e55 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -1,6 +1,7 @@
#include "slang-parser.h"
#include "../core/slang-semantic-version.h"
+#include "slang-check-impl.h"
#include "slang-compiler.h"
#include "slang-lookup-spirv.h"
#include "slang-lookup.h"
@@ -75,11 +76,18 @@ enum Precedence : int
Postfix,
};
+enum class ParsingStage
+{
+ Decl,
+ Body,
+};
+
struct ParserOptions
{
bool enableEffectAnnotations = false;
bool allowGLSLInput = false;
bool isInLanguageServer = false;
+ ParsingStage stage = ParsingStage::Body;
CompilerOptionSet optionSet;
};
@@ -91,6 +99,7 @@ public:
NamePool* namePool;
SourceLanguage sourceLanguage;
ASTBuilder* astBuilder;
+ SemanticsVisitor* semanticsVisitor = nullptr;
NamePool* getNamePool() { return namePool; }
SourceLanguage getSourceLanguage() { return sourceLanguage; }
@@ -156,6 +165,8 @@ public:
resetLookupScope();
}
+ ParsingStage getStage() { return options.stage; }
+
ModuleDecl* getCurrentModuleDecl() { return currentModule; }
Parser(
@@ -1811,14 +1822,62 @@ static Stmt* parseOptBody(Parser* parser)
if (peekTokenType(parser) == TokenType::LBrace)
{
parser->sink->diagnose(semiColonToken.loc, Diagnostics::unexpectedBodyAfterSemicolon);
- return parser->parseBlockStatement();
+
+ // Fall through to parse the block stmt.
+ }
+ else
+ {
+ return nullptr;
}
- return nullptr;
}
- else
+
+ if (parser->getStage() == ParsingStage::Decl)
{
- return parser->parseBlockStatement();
+ // If we are at the initial parsing stage, just collect the tokens
+ // without actually parsing them.
+ if (peekTokenType(parser) != TokenType::LBrace)
+ {
+ return parser->parseBlockStatement();
+ }
+ auto unparsedStmt = parser->astBuilder->create<UnparsedStmt>();
+ unparsedStmt->currentScope = parser->currentScope;
+ unparsedStmt->outerScope = parser->outerScope;
+ unparsedStmt->sourceLanguage = parser->getSourceLanguage();
+ unparsedStmt->isInVariadicGenerics = parser->isInVariadicGenerics;
+ parser->FillPosition(unparsedStmt);
+ List<Token>& tokens = unparsedStmt->tokens;
+ int braceDepth = 0;
+ for (;;)
+ {
+ auto token = parser->ReadToken();
+ if (token.type == TokenType::EndOfFile)
+ {
+ break;
+ }
+ if (token.type == TokenType::LBrace)
+ {
+ braceDepth++;
+ }
+ else if (token.type == TokenType::RBrace)
+ {
+ braceDepth--;
+ }
+ tokens.add(token);
+ if (braceDepth == 0)
+ {
+ break;
+ }
+ }
+ Token eofToken;
+ eofToken.type = TokenType::EndOfFile;
+ eofToken.loc = parser->tokenReader.peekLoc();
+ tokens.add(eofToken);
+ return unparsedStmt;
}
+
+ // If we are in the second stage of parsing, then we need to actually
+ // parse the block statement for real.
+ return parser->parseBlockStatement();
}
/// Complete parsing of a function using traditional (C-like) declarator syntax
@@ -1867,9 +1926,12 @@ static Decl* parseTraditionalFuncDecl(Parser* parser, DeclaratorInfo const& decl
parser->PushScope(funcScope);
decl->body = parseOptBody(parser);
- if (auto block = as<BlockStmt>(decl->body))
+ if (auto blockStmt = as<BlockStmt>(decl->body))
+ decl->closingSourceLoc = blockStmt->closingSourceLoc;
+ else if (auto unparsedStmt = as<UnparsedStmt>(decl->body))
{
- decl->closingSourceLoc = block->closingSourceLoc;
+ if (unparsedStmt->tokens.getCount())
+ decl->closingSourceLoc = unparsedStmt->tokens.getLast().getLoc();
}
parser->PopScope();
@@ -2311,15 +2373,79 @@ static bool isGenericName(Parser* parser, Name* name)
return lookupResult.item.declRef.is<GenericDecl>();
}
+enum class BaseGenericKind
+{
+ Unknown,
+ Generic,
+ NonGeneric,
+};
+
static Expr* tryParseGenericApp(Parser* parser, Expr* base)
{
Name* baseName = nullptr;
- if (auto varExpr = as<VarExpr>(base))
- baseName = varExpr->name;
- // if base is a known generics, parse as generics
- if (baseName && isGenericName(parser, baseName))
+ BaseGenericKind baseKind = BaseGenericKind::Unknown;
+ if (parser->semanticsVisitor)
+ {
+ // If we have access to a semantic visitor, we can check the base
+ // and see if it refers to a generic.
+ auto checkedBase = parser->semanticsVisitor->CheckTerm(base);
+ if (auto declRefExpr = as<DeclRefExpr>(checkedBase))
+ {
+ if (declRefExpr->declRef.is<GenericDecl>())
+ {
+ baseKind = BaseGenericKind::Generic;
+ }
+ else if (
+ declRefExpr->declRef.is<FunctionDeclBase>() ||
+ declRefExpr->declRef.is<AggTypeDeclBase>())
+ {
+ // If declref is a function or type, even if it is not a generic,
+ // we should parse the `<` as a generic application for better error
+ // messages. This is because functions or types can never precede a
+ // `<` in valid Slang code, and it is more likely that the user assumed
+ // the function or type is generic by mistake.
+ //
+ baseKind = BaseGenericKind::Generic;
+ }
+ else
+ {
+ baseKind = BaseGenericKind::NonGeneric;
+ }
+ }
+ else if (auto overloadedExpr = as<OverloadedExpr>(checkedBase))
+ {
+ baseKind = BaseGenericKind::NonGeneric;
+ for (auto candidate : overloadedExpr->lookupResult2)
+ {
+ if (candidate.declRef.is<GenericDecl>() ||
+ declRefExpr->declRef.is<FunctionDeclBase>() ||
+ declRefExpr->declRef.is<AggTypeDeclBase>())
+ {
+ baseKind = BaseGenericKind::Generic;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Without a semantic visitor, we fallback to a more simplistic lookup
+ // and guessing.
+ if (auto varExpr = as<VarExpr>(base))
+ baseName = varExpr->name;
+ // if base is a known generics, parse as generics
+ if (baseName && isGenericName(parser, baseName))
+ baseKind = BaseGenericKind::Generic;
+ }
+
+ // If base is known to be a generic, just parse as generic app.
+ if (baseKind == BaseGenericKind::Generic)
return parseGenericApp(parser, base);
+ // If base is known to be non-generic, just return base.
+ if (baseKind == BaseGenericKind::NonGeneric)
+ return base;
+
// otherwise, we speculate as generics, and fallback to comparison when parsing failed
TokenSpan tokenSpan;
tokenSpan.m_begin = parser->tokenReader.m_cursor;
@@ -3844,8 +3970,13 @@ static NodeBase* parseConstructorDecl(Parser* parser, void* /*userData*/)
decl->body = parseOptBody(parser);
- if (auto block = as<BlockStmt>(decl->body))
- decl->closingSourceLoc = block->closingSourceLoc;
+ if (auto blockStmt = as<BlockStmt>(decl->body))
+ decl->closingSourceLoc = blockStmt->closingSourceLoc;
+ else if (auto unparsedStmt = as<UnparsedStmt>(decl->body))
+ {
+ if (unparsedStmt->tokens.getCount())
+ decl->closingSourceLoc = unparsedStmt->tokens.getLast().getLoc();
+ }
parser->PopScope();
return decl;
@@ -3898,10 +4029,13 @@ static AccessorDecl* parseAccessorDecl(Parser* parser)
if (parser->tokenReader.peekTokenType() == TokenType::LBrace)
{
- decl->body = parser->parseBlockStatement();
- if (auto block = as<BlockStmt>(decl->body))
+ decl->body = parseOptBody(parser);
+ if (auto blockStmt = as<BlockStmt>(decl->body))
+ decl->closingSourceLoc = blockStmt->closingSourceLoc;
+ else if (auto unparsedStmt = as<UnparsedStmt>(decl->body))
{
- decl->closingSourceLoc = block->closingSourceLoc;
+ if (unparsedStmt->tokens.getCount())
+ decl->closingSourceLoc = unparsedStmt->tokens.getLast().getLoc();
}
}
else
@@ -4184,6 +4318,11 @@ static NodeBase* parseFuncDecl(Parser* parser, void* /*userData*/)
decl->body = parseOptBody(parser);
if (auto blockStmt = as<BlockStmt>(decl->body))
decl->closingSourceLoc = blockStmt->closingSourceLoc;
+ else if (auto unparsedStmt = as<UnparsedStmt>(decl->body))
+ {
+ if (unparsedStmt->tokens.getCount())
+ decl->closingSourceLoc = unparsedStmt->tokens.getLast().getLoc();
+ }
parser->PopScope();
return decl;
});
@@ -4734,6 +4873,19 @@ static void CompleteDecl(
AddMember(containerDecl, decl);
}
}
+
+ if (parser->semanticsVisitor && parser->getStage() == ParsingStage::Body)
+ {
+ // When we are in a deferred parsing stage for function bodies,
+ // we will mark all local var decls as `ReadyForParserLookup` so they can
+ // be returned via lookup.
+ // Note that our lookup logic will ignore all unchecked decls, but during
+ // parsing we don't want to ignore them, so we mark them as `ReadyForParserLookup`
+ // here, which is a pseudo state that is only used during parsing.
+ // Before checking the decl in semantic checking, we will mark them back as
+ // `Unchecked`.
+ decl->checkState = DeclCheckState::ReadyForParserLookup;
+ }
}
static DeclBase* ParseDeclWithModifiers(
@@ -5482,6 +5634,7 @@ Stmt* parseCompileTimeForStmt(Parser* parser)
VarDecl* varDecl = parser->astBuilder->create<VarDecl>();
varDecl->nameAndLoc = varNameAndLoc;
varDecl->loc = varNameAndLoc.loc;
+ varDecl->checkState = DeclCheckState::ReadyForParserLookup;
stmt->varDecl = varDecl;
@@ -5863,7 +6016,6 @@ DeclStmt* Parser::parseVarDeclrStatement(Modifiers modifiers)
{
sink->diagnose(decl->loc, Diagnostics::declNotAllowed, decl->astNodeType);
}
-
return varDeclrStatement;
}
@@ -5902,6 +6054,11 @@ Stmt* Parser::parseIfLetStatement()
tempVarDecl->nameAndLoc = NameLoc(getName(this, "$OptVar"), identifierToken.loc);
tempVarDecl->initExpr = initExpr;
AddMember(currentScope->containerDecl, tempVarDecl);
+ if (semanticsVisitor)
+ semanticsVisitor->ensureDecl(
+ (Decl*)tempVarDecl,
+ DeclCheckState::DefinitionChecked,
+ nullptr);
DeclStmt* tmpVarDeclStmt = astBuilder->create<DeclStmt>();
FillPosition(tmpVarDeclStmt);
@@ -6991,9 +7148,19 @@ static Expr* parseAtomicExpr(Parser* parser)
// as an expression.
Expr* base = nullptr;
- if (!tryParseExpression(parser, base, TokenType::RParent))
+ if (parser->LookAheadToken(TokenType::RParent))
+ {
+ // We don't support empty parentheses `()` as a valid expression.
+ parser->diagnose(openParen, Diagnostics::invalidEmptyParenthesisExpr);
+ base = parser->astBuilder->create<IncompleteExpr>();
+ base->type = parser->astBuilder->getErrorType();
+ }
+ else
{
- base = parser->ParseType();
+ if (!tryParseExpression(parser, base, TokenType::RParent))
+ {
+ base = parser->ParseType();
+ }
}
parser->ReadToken(TokenType::RParent);
@@ -8086,6 +8253,7 @@ Expr* parseTermFromSourceFile(
{
ParserOptions options;
options.allowGLSLInput = sourceLanguage == SourceLanguage::GLSL;
+ options.stage = ParsingStage::Body;
Parser parser(astBuilder, tokens, sink, outerScope, options);
parser.currentScope = outerScope;
parser.namePool = namePool;
@@ -8093,6 +8261,39 @@ Expr* parseTermFromSourceFile(
return parser.ParseExpression();
}
+Stmt* parseUnparsedStmt(
+ ASTBuilder* astBuilder,
+ SemanticsVisitor* semanticsVisitor,
+ TranslationUnitRequest* translationUnit,
+ SourceLanguage sourceLanguage,
+ bool isInVariadicGenerics,
+ TokenSpan const& tokens,
+ DiagnosticSink* sink,
+ Scope* currentScope,
+ Scope* outerScope)
+{
+ ParserOptions options = {};
+ options.stage = ParsingStage::Body;
+ options.enableEffectAnnotations = translationUnit->compileRequest->optionSet.getBoolOption(
+ CompilerOptionName::EnableEffectAnnotations);
+ options.allowGLSLInput =
+ translationUnit->compileRequest->optionSet.getBoolOption(CompilerOptionName::AllowGLSL) ||
+ sourceLanguage == SourceLanguage::GLSL;
+ options.isInLanguageServer =
+ translationUnit->compileRequest->getLinkage()->isInLanguageServer();
+ options.optionSet = translationUnit->compileRequest->optionSet;
+
+ Parser parser(astBuilder, tokens, sink, outerScope, options);
+ parser.currentScope = outerScope;
+ parser.namePool = translationUnit->getNamePool();
+ parser.sourceLanguage = sourceLanguage;
+ parser.semanticsVisitor = semanticsVisitor;
+ parser.currentScope = parser.currentLookupScope = currentScope;
+ parser.currentModule = semanticsVisitor->getShared()->getModule()->getModuleDecl();
+ parser.isInVariadicGenerics = isInVariadicGenerics;
+ return parser.parseBlockStatement();
+}
+
// Parse a source file into an existing translation unit
void parseSourceFile(
ASTBuilder* astBuilder,
@@ -8104,6 +8305,7 @@ void parseSourceFile(
ContainerDecl* parentDecl)
{
ParserOptions options = {};
+ options.stage = ParsingStage::Decl;
options.enableEffectAnnotations = translationUnit->compileRequest->optionSet.getBoolOption(
CompilerOptionName::EnableEffectAnnotations);
options.allowGLSLInput =
diff --git a/source/slang/slang-parser.h b/source/slang/slang-parser.h
index bef03c9fe..9f9f4972a 100644
--- a/source/slang/slang-parser.h
+++ b/source/slang/slang-parser.h
@@ -25,6 +25,19 @@ Expr* parseTermFromSourceFile(
NamePool* namePool,
SourceLanguage sourceLanguage);
+struct SemanticsVisitor;
+
+Stmt* parseUnparsedStmt(
+ ASTBuilder* astBuilder,
+ SemanticsVisitor* semantics,
+ TranslationUnitRequest* translationUnit,
+ SourceLanguage sourceLanguage,
+ bool isInVariadicGenerics,
+ TokenSpan const& tokens,
+ DiagnosticSink* sink,
+ Scope* currentScope,
+ Scope* outerScope);
+
ModuleDecl* populateBaseLanguageModule(ASTBuilder* astBuilder, Scope* scope);
/// Information used to set up SyntaxDecl. Such decls