From f69bc6cdb10aab2d1b202668cb7ecbcc0ddf33f2 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Fri, 7 Jul 2017 14:30:26 -0700 Subject: Fully parse function bodies, even in "rewriter" mode This is in anticipation of needing to have more complete knowledge to be able to handle user code that `import`s library functionality. The big picture of this change is just to remove the `UnparsedStmt` class that was used to hold the bodies of user functions as opaque token streams, and thus to let the full parser and compiler loose on that code. That is the easy part, of course, and the hard part is all the fixes that this requires in the rest of the compielr to make this even remotely work. Subsequent commit address a lot of other issues, so this particular commit mostly represents work-in-progress. One detail is that this change puts a conditional around nearly every diagnostic message in `check.cpp` to suppress thing when in rewriter mode. I have yet to check how that works out if there are errors in anything we actually need to understand for the purposes of generating reflection data. --- source/slang/check.cpp | 419 +++++++++++++++++++++++++++++-------------------- 1 file changed, 248 insertions(+), 171 deletions(-) (limited to 'source/slang/check.cpp') diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 7c67473be..f21f9480c 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -243,14 +243,16 @@ namespace Slang if (lookupResult.isOverloaded()) { // We had an ambiguity anyway, so report it. - getSink()->diagnose(overloadedExpr, Diagnostics::ambiguousReference, lookupResult.items[0].declRef.GetName()); - - for(auto item : lookupResult.items) + if (!isRewriteMode()) { - String declString = getDeclSignatureString(item); - getSink()->diagnose(item.declRef, Diagnostics::overloadCandidate, declString); - } + getSink()->diagnose(overloadedExpr, Diagnostics::ambiguousReference, lookupResult.items[0].declRef.GetName()); + for(auto item : lookupResult.items) + { + String declString = getDeclSignatureString(item); + getSink()->diagnose(item.declRef, Diagnostics::overloadCandidate, declString); + } + } // TODO(tfoley): should we construct a new ErrorExpr here? overloadedExpr->Type = QualType(ExpressionType::Error); return overloadedExpr; @@ -276,9 +278,11 @@ namespace Slang return expr; } - getSink()->diagnose(expr, Diagnostics::unimplemented, "expected a type"); - // TODO: construct some kind of `ErrorExpr`? - return expr; + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::unimplemented, "expected a type"); + } + return CreateErrorExpr(expr); } RefPtr ExpectAType(RefPtr expr) @@ -424,7 +428,10 @@ namespace Slang { if (outProperType) { - getSink()->diagnose(typeExp.exp.Ptr(), Diagnostics::unimplemented, "can't fill in default for generic type parameter"); + if (!isRewriteMode()) + { + getSink()->diagnose(typeExp.exp.Ptr(), Diagnostics::unimplemented, "can't fill in default for generic type parameter"); + } *outProperType = ExpressionType::Error; } return false; @@ -440,7 +447,10 @@ namespace Slang { if (outProperType) { - getSink()->diagnose(typeExp.exp.Ptr(), Diagnostics::unimplemented, "can't fill in default for generic type parameter"); + if (!isRewriteMode()) + { + getSink()->diagnose(typeExp.exp.Ptr(), Diagnostics::unimplemented, "can't fill in default for generic type parameter"); + } *outProperType = ExpressionType::Error; } return false; @@ -511,7 +521,10 @@ namespace Slang if (basicType->BaseType == BaseType::Void) { // TODO(tfoley): pick the right diagnostic message - getSink()->diagnose(result.exp.Ptr(), Diagnostics::invalidTypeVoid); + if (!isRewriteMode()) + { + getSink()->diagnose(result.exp.Ptr(), Diagnostics::invalidTypeVoid); + } result.type = ExpressionType::Error; return result; } @@ -634,7 +647,9 @@ namespace Slang CASE(Int, Signed, Int32); CASE(UInt, Unsigned, Int32); CASE(UInt64, Unsigned, Int64); + CASE(Half, Float, Int16); CASE(Float, Float, Int32); + CASE(Double, Float, Int64); CASE(Void, Error, Error); #undef CASE @@ -972,7 +987,7 @@ namespace Slang RefPtr toType, RefPtr fromExpr) { - auto castExpr = new TypeCastExpressionSyntaxNode(); + auto castExpr = new ImplicitCastExpr(); castExpr->Position = fromExpr->Position; castExpr->TargetType.type = toType; castExpr->Type = QualType(toType); @@ -980,6 +995,10 @@ namespace Slang return castExpr; } + bool isRewriteMode() + { + return (getTranslationUnit()->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING) != 0; + } // Perform type coercion, and emit errors if it isn't possible RefPtr Coerce( @@ -990,7 +1009,7 @@ namespace Slang // expressions without a type, and we need to ignore them. if( !fromExpr->Type.type ) { - if(getTranslationUnit()->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING ) + if(isRewriteMode()) return fromExpr; } @@ -1002,7 +1021,7 @@ namespace Slang fromExpr.Ptr(), nullptr)) { - if(!(getTranslationUnit()->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING)) + if(!isRewriteMode()) { getSink()->diagnose(fromExpr->Position, Diagnostics::typeMismatch, toType, fromExpr->Type); } @@ -1041,13 +1060,20 @@ namespace Slang else { // TODO: infer a type from the initializers + if (!initExpr) { - getSink()->diagnose(varDecl, Diagnostics::unimplemented, "variable declaration with no type must have initializer"); + if (!isRewriteMode()) + { + getSink()->diagnose(varDecl, Diagnostics::unimplemented, "variable declaration with no type must have initializer"); + } } else { - getSink()->diagnose(varDecl, Diagnostics::unimplemented, "type inference for variable declaration"); + if (!isRewriteMode()) + { + getSink()->diagnose(varDecl, Diagnostics::unimplemented, "type inference for variable declaration"); + } } } @@ -1122,7 +1148,10 @@ namespace Slang // If type expression didn't name an interface, we'll emit an error here // TODO: deal with the case of an error in the type expression (don't cascade) - getSink()->diagnose( base.exp, Diagnostics::expectedAnInterfaceGot, base.type); + if (!isRewriteMode()) + { + getSink()->diagnose( base.exp, Diagnostics::expectedAnInterfaceGot, base.type); + } } RefPtr checkConstantIntVal( @@ -1138,7 +1167,10 @@ namespace Slang auto constIntVal = intVal.As(); if(!constIntVal) { - getSink()->diagnose(expr->Position, Diagnostics::expectedIntegerConstantNotLiteral); + if (!isRewriteMode()) + { + getSink()->diagnose(expr->Position, Diagnostics::expectedIntegerConstantNotLiteral); + } return nullptr; } return constIntVal; @@ -1503,7 +1535,10 @@ namespace Slang if (!funcDecl->ReturnType.Equals(prevFuncDecl->ReturnType)) { // Bad dedeclaration - getSink()->diagnose(funcDecl, Diagnostics::unimplemented, "redeclaration has a different return type"); + if (!isRewriteMode()) + { + getSink()->diagnose(funcDecl, Diagnostics::unimplemented, "redeclaration has a different return type"); + } // Don't bother emitting other errors at this point break; @@ -1517,7 +1552,10 @@ namespace Slang if (funcDecl->Body && prevFuncDecl->Body) { // Redefinition - getSink()->diagnose(funcDecl, Diagnostics::unimplemented, "function redefinition"); + if (!isRewriteMode()) + { + getSink()->diagnose(funcDecl, Diagnostics::unimplemented, "function redefinition"); + } // Don't bother emitting other errors break; @@ -1539,7 +1577,12 @@ namespace Slang para->Type = CheckUsableType(para->Type); if (para->Type.Equals(ExpressionType::GetVoid())) - getSink()->diagnose(para, Diagnostics::parameterCannotBeVoid); + { + if (!isRewriteMode()) + { + getSink()->diagnose(para, Diagnostics::parameterCannotBeVoid); + } + } } void VisitFunctionDeclaration(FunctionSyntaxNode *functionNode) @@ -1556,7 +1599,12 @@ namespace Slang checkDecl(para); if (paraNames.Contains(para->Name.Content)) - getSink()->diagnose(para, Diagnostics::parameterAlreadyDefined, para->Name); + { + if (!isRewriteMode()) + { + getSink()->diagnose(para, Diagnostics::parameterAlreadyDefined, para->Name); + } + } else paraNames.Add(para->Name.Content); } @@ -1613,7 +1661,10 @@ namespace Slang auto outer = FindOuterStmt(); if (!outer) { - getSink()->diagnose(stmt, Diagnostics::breakOutsideLoop); + if (!isRewriteMode()) + { + getSink()->diagnose(stmt, Diagnostics::breakOutsideLoop); + } } stmt->parentStmt = outer; } @@ -1622,7 +1673,10 @@ namespace Slang auto outer = FindOuterStmt(); if (!outer) { - getSink()->diagnose(stmt, Diagnostics::continueOutsideLoop); + if (!isRewriteMode()) + { + getSink()->diagnose(stmt, Diagnostics::continueOutsideLoop); + } } stmt->parentStmt = outer; } @@ -1691,7 +1745,10 @@ namespace Slang if (!switchStmt) { - getSink()->diagnose(stmt, Diagnostics::caseOutsideSwitch); + if (!isRewriteMode()) + { + getSink()->diagnose(stmt, Diagnostics::caseOutsideSwitch); + } } else { @@ -1707,7 +1764,10 @@ namespace Slang auto switchStmt = FindOuterStmt(); if (!switchStmt) { - getSink()->diagnose(stmt, Diagnostics::defaultOutsideSwitch); + if (!isRewriteMode()) + { + getSink()->diagnose(stmt, Diagnostics::defaultOutsideSwitch); + } } stmt->parentStmt = switchStmt; } @@ -1718,12 +1778,6 @@ namespace Slang checkStmt(stmt->NegativeStatement); } - void visitUnparsedStmt(UnparsedStmt*) - { - // Nothing to do - } - - void visitEmptyStatementSyntaxNode(EmptyStatementSyntaxNode*) { // Nothing to do @@ -1739,7 +1793,12 @@ namespace Slang if (!stmt->Expression) { if (function && !function->ReturnType.Equals(ExpressionType::GetVoid())) - getSink()->diagnose(stmt, Diagnostics::returnNeedsExpression); + { + if (!isRewriteMode()) + { + getSink()->diagnose(stmt, Diagnostics::returnNeedsExpression); + } + } } else { @@ -1832,7 +1891,10 @@ namespace Slang // TODO(tfoley): How to handle the case where bound isn't known? if (GetMinBound(elementCount) <= 0) { - getSink()->diagnose(varDecl, Diagnostics::invalidArraySize); + if (!isRewriteMode()) + { + getSink()->diagnose(varDecl, Diagnostics::invalidArraySize); + } return; } } @@ -1853,7 +1915,12 @@ namespace Slang #endif varDecl->Type = typeExp; if (varDecl->Type.Equals(ExpressionType::GetVoid())) - getSink()->diagnose(varDecl, Diagnostics::invalidTypeVoid); + { + if (!isRewriteMode()) + { + getSink()->diagnose(varDecl, Diagnostics::invalidTypeVoid); + } + } if(auto initExpr = varDecl->Expr) { @@ -2160,7 +2227,10 @@ namespace Slang auto result = TryCheckIntegerConstantExpression(expr.Ptr()); if (!result) { - getSink()->diagnose(expr, Diagnostics::expectedIntegerConstantNotConstant); + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::expectedIntegerConstantNotConstant); + } } return result; } @@ -2177,7 +2247,10 @@ namespace Slang if (!indexExpr->Type->Equals(ExpressionType::GetInt()) && !indexExpr->Type->Equals(ExpressionType::GetUInt())) { - getSink()->diagnose(indexExpr, Diagnostics::subscriptIndexNonInteger); + if (!isRewriteMode()) + { + getSink()->diagnose(indexExpr, Diagnostics::subscriptIndexNonInteger); + } return CreateErrorExpr(subscriptExpr.Ptr()); } @@ -2320,7 +2393,10 @@ namespace Slang fail: { - getSink()->diagnose(subscriptExpr, Diagnostics::subscriptNonArray, baseType); + if (!isRewriteMode()) + { + getSink()->diagnose(subscriptExpr, Diagnostics::subscriptNonArray, baseType); + } return CreateErrorExpr(subscriptExpr); } } @@ -2419,6 +2495,16 @@ namespace Slang return appExpr; } + RefPtr visitParenExpr(ParenExpr* expr) + { + auto base = expr->base; + base = CheckTerm(base); + + expr->base = base; + expr->Type = base->Type; + return expr; + } + // RefPtr visitAssignExpr(AssignExpr* expr) @@ -2431,7 +2517,10 @@ namespace Slang if (!type.IsLeftValue) { - getSink()->diagnose(expr, Diagnostics::assignNonLValue); + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::assignNonLValue); + } } expr->Type = type; return expr; @@ -2460,7 +2549,10 @@ namespace Slang } else { - getSink()->diagnose(decl->targetType.exp, Diagnostics::unimplemented, "expected a nominal type here"); + if (!isRewriteMode()) + { + getSink()->diagnose(decl->targetType.exp, Diagnostics::unimplemented, "expected a nominal type here"); + } } } else if (decl->targetType->Equals(ExpressionType::Error)) @@ -2469,7 +2561,10 @@ namespace Slang } else { - getSink()->diagnose(decl->targetType.exp, Diagnostics::unimplemented, "expected a nominal type here"); + if (!isRewriteMode()) + { + getSink()->diagnose(decl->targetType.exp, Diagnostics::unimplemented, "expected a nominal type here"); + } } decl->SetCheckState(DeclCheckState::CheckedHeader); @@ -3073,12 +3168,18 @@ namespace Slang { if (argCount < paramCounts.required) { - getSink()->diagnose(context.appExpr, Diagnostics::notEnoughArguments, argCount, paramCounts.required); + if (!isRewriteMode()) + { + getSink()->diagnose(context.appExpr, Diagnostics::notEnoughArguments, argCount, paramCounts.required); + } } else { assert(argCount > paramCounts.allowed); - getSink()->diagnose(context.appExpr, Diagnostics::tooManyArguments, argCount, paramCounts.allowed); + if (!isRewriteMode()) + { + getSink()->diagnose(context.appExpr, Diagnostics::tooManyArguments, argCount, paramCounts.allowed); + } } } @@ -3100,8 +3201,11 @@ namespace Slang if (context.mode != OverloadResolveContext::Mode::JustTrying) { - getSink()->diagnose(context.appExpr, Diagnostics::expectedPrefixOperator); - getSink()->diagnose(decl, Diagnostics::seeDefinitionOf, decl->getName()); + if (!isRewriteMode()) + { + getSink()->diagnose(context.appExpr, Diagnostics::expectedPrefixOperator); + getSink()->diagnose(decl, Diagnostics::seeDefinitionOf, decl->getName()); + } } return false; @@ -3113,8 +3217,11 @@ namespace Slang if (context.mode != OverloadResolveContext::Mode::JustTrying) { - getSink()->diagnose(context.appExpr, Diagnostics::expectedPostfixOperator); - getSink()->diagnose(decl, Diagnostics::seeDefinitionOf, decl->getName()); + if (!isRewriteMode()) + { + getSink()->diagnose(context.appExpr, Diagnostics::expectedPostfixOperator); + getSink()->diagnose(decl, Diagnostics::seeDefinitionOf, decl->getName()); + } } return false; @@ -3311,13 +3418,16 @@ namespace Slang if (candidate.status == OverloadCandidate::Status::GenericArgumentInferenceFailed) { String callString = GetCallSignatureString(context.appExpr); - getSink()->diagnose( - context.appExpr, - Diagnostics::genericArgumentInferenceFailed, - callString); + if (!isRewriteMode()) + { + getSink()->diagnose( + context.appExpr, + Diagnostics::genericArgumentInferenceFailed, + callString); - String declString = getDeclSignatureString(candidate.item); - getSink()->diagnose(candidate.item.declRef, Diagnostics::genericSignatureTried, declString); + String declString = getDeclSignatureString(candidate.item); + getSink()->diagnose(candidate.item.declRef, Diagnostics::genericSignatureTried, declString); + } goto error; } @@ -4223,6 +4333,14 @@ namespace Slang { return CreateErrorExpr(expr); } + // If any of the arguments is an error, then we should bail out, to avoid + // cascading errors where we successfully pick an overload, but not the one + // the user meant. + for (auto arg : expr->Arguments) + { + if (IsErrorExpr(arg)) + return CreateErrorExpr(expr); + } OverloadResolveContext context; context.appExpr = expr; @@ -4268,11 +4386,17 @@ namespace Slang // We will construct a diagnostic message to help out. if (funcName.Length() != 0) { - getSink()->diagnose(expr, Diagnostics::noApplicableOverloadForNameWithArgs, funcName, argsList); + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::noApplicableOverloadForNameWithArgs, funcName, argsList); + } } else { - getSink()->diagnose(expr, Diagnostics::noApplicableWithArgs, argsList); + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::noApplicableWithArgs, argsList); + } } } else @@ -4281,32 +4405,41 @@ namespace Slang if (funcName.Length() != 0) { - getSink()->diagnose(expr, Diagnostics::ambiguousOverloadForNameWithArgs, funcName, argsList); + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::ambiguousOverloadForNameWithArgs, funcName, argsList); + } } else { - getSink()->diagnose(expr, Diagnostics::ambiguousOverloadWithArgs, argsList); + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::ambiguousOverloadWithArgs, argsList); + } } } - UInt candidateCount = context.bestCandidates.Count(); - UInt maxCandidatesToPrint = 10; // don't show too many candidates at once... - UInt candidateIndex = 0; - for (auto candidate : context.bestCandidates) + if (!isRewriteMode()) { - String declString = getDeclSignatureString(candidate.item); + UInt candidateCount = context.bestCandidates.Count(); + UInt maxCandidatesToPrint = 10; // don't show too many candidates at once... + UInt candidateIndex = 0; + for (auto candidate : context.bestCandidates) + { + String declString = getDeclSignatureString(candidate.item); - declString = declString + "[" + String(candidate.conversionCostSum) + "]"; + declString = declString + "[" + String(candidate.conversionCostSum) + "]"; - getSink()->diagnose(candidate.item.declRef, Diagnostics::overloadCandidate, declString); + getSink()->diagnose(candidate.item.declRef, Diagnostics::overloadCandidate, declString); - candidateIndex++; - if (candidateIndex == maxCandidatesToPrint) - break; - } - if (candidateIndex != candidateCount) - { - getSink()->diagnose(expr, Diagnostics::moreOverloadCandidates, candidateCount - candidateIndex); + candidateIndex++; + if (candidateIndex == maxCandidatesToPrint) + break; + } + if (candidateIndex != candidateCount) + { + getSink()->diagnose(expr, Diagnostics::moreOverloadCandidates, candidateCount - candidateIndex); + } } return CreateErrorExpr(expr); @@ -4322,7 +4455,10 @@ namespace Slang else { // Nothing at all was found that we could even consider invoking - getSink()->diagnose(expr->FunctionExpr, Diagnostics::expectedFunction); + if (!isRewriteMode()) + { + getSink()->diagnose(expr->FunctionExpr, Diagnostics::expectedFunction); + } expr->Type = QualType(ExpressionType::Error); return expr; } @@ -4417,7 +4553,10 @@ namespace Slang // TODO(tfoley): print a reasonable message here... - getSink()->diagnose(genericAppExpr, Diagnostics::unimplemented, "no applicable generic"); + if (!isRewriteMode()) + { + getSink()->diagnose(genericAppExpr, Diagnostics::unimplemented, "no applicable generic"); + } return CreateErrorExpr(genericAppExpr); } @@ -4448,76 +4587,12 @@ namespace Slang else { // Nothing at all was found that we could even consider invoking - getSink()->diagnose(genericAppExpr, Diagnostics::unimplemented, "expected a generic"); - return CreateErrorExpr(genericAppExpr); - } - - -#if TIMREMOVED - - if (IsErrorExpr(base)) - { - return CreateErrorExpr(typeNode); - } - else if(auto baseDeclRefExpr = base.As()) - { - auto declRef = baseDeclRefExpr->declRef; - - if (auto genericDeclRef = declRef.As()) + if (!isRewriteMode()) { - int argCount = typeNode->Args.Count(); - int argIndex = 0; - for (RefPtr member : genericDeclRef.getDecl()->Members) - { - if (auto typeParam = member.As()) - { - if (argIndex == argCount) - { - // Too few arguments! - - } - - // TODO: checking! - } - else if (auto valParam = member.As()) - { - // TODO: checking - } - else - { - - } - } - if (argIndex != argCount) - { - // Too many arguments! - } - - // Now instantiate the declaration given those arguments - auto type = InstantiateGenericType(genericDeclRef, args); - typeResult = type; - typeNode->Type = new TypeExpressionType(type); - return typeNode; - } - } - else if (auto overloadedExpr = base.As()) - { - // We are referring to a bunch of declarations, each of which might be generic - LookupResult result; - for (auto item : overloadedExpr->lookupResult2.items) - { - auto applied = TryApplyGeneric(item, typeNode); - if (!applied) - continue; - - AddToLookupResult(result, appliedItem); + getSink()->diagnose(genericAppExpr, Diagnostics::unimplemented, "expected a generic"); } + return CreateErrorExpr(genericAppExpr); } - - // TODO: correct diagnostic here! - getSink()->diagnose(typeNode, Diagnostics::expectedAGeneric, base->Type); - return CreateErrorExpr(typeNode); -#endif } RefPtr visitSharedTypeExpr(SharedTypeExpr* expr) @@ -4568,7 +4643,10 @@ namespace Slang if (i < expr->Arguments.Count() && expr->Arguments[i]->Type->AsBasicType() && !expr->Arguments[i]->Type.IsLeftValue) { - getSink()->diagnose(expr->Arguments[i], Diagnostics::argumentExpectedLValue, (*params)[i]->Name); + if (!isRewriteMode()) + { + getSink()->diagnose(expr->Arguments[i], Diagnostics::argumentExpectedLValue, (*params)[i]->Name); + } } } } @@ -4610,7 +4688,10 @@ namespace Slang expr); } - getSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->name); + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::undefinedIdentifier2, expr->name); + } return expr; } @@ -4651,32 +4732,13 @@ namespace Slang fail: // Default: in no other case succeds, then the cast failed and we emit a diagnostic. - getSink()->diagnose(expr, Diagnostics::invalidTypeCast, expr->Expression->Type, targetType->ToString()); - expr->Type = QualType(ExpressionType::Error); - return expr; - } -#if TIMREMOVED - virtual RefPtr VisitSelectExpression(SelectExpressionSyntaxNode * expr) override - { - auto selectorExpr = expr->SelectorExpr; - selectorExpr = CheckExpr(selectorExpr); - selectorExpr = Coerce(ExpressionType::GetBool(), selectorExpr); - expr->SelectorExpr = selectorExpr; - - // TODO(tfoley): We need a general purpose "join" on types for inferring - // generic argument types for builtins/intrinsics, so this should really - // be using the exact same logic... - // - expr->Expr0 = expr->Expr0->Accept(this).As(); - expr->Expr1 = expr->Expr1->Accept(this).As(); - if (!expr->Expr0->Type->Equals(expr->Expr1->Type.Ptr())) + if (!isRewriteMode()) { - getSink()->diagnose(expr, Diagnostics::selectValuesTypeMismatch); + getSink()->diagnose(expr, Diagnostics::invalidTypeCast, expr->Expression->Type, targetType->ToString()); } - expr->Type = expr->Expr0->Type; + expr->Type = QualType(ExpressionType::Error); return expr; } -#endif // Get the type to use when referencing a declaration QualType GetTypeForDeclRef(DeclRef declRef) @@ -4771,7 +4833,10 @@ namespace Slang case 'w': case 'a': elementIndex = 3; break; default: // An invalid character in the swizzle is an error - getSink()->diagnose(swizExpr, Diagnostics::unimplemented, "invalid component name for swizzle"); + if (!isRewriteMode()) + { + getSink()->diagnose(swizExpr, Diagnostics::unimplemented, "invalid component name for swizzle"); + } anyError = true; continue; } @@ -4782,7 +4847,10 @@ namespace Slang // Make sure the index is in range for the source type if (elementIndex >= limitElement) { - getSink()->diagnose(swizExpr, Diagnostics::unimplemented, "swizzle component out of range for type"); + if (!isRewriteMode()) + { + getSink()->diagnose(swizExpr, Diagnostics::unimplemented, "swizzle component out of range for type"); + } anyError = true; continue; } @@ -4806,7 +4874,7 @@ namespace Slang if (anyError) { - swizExpr->Type = QualType(ExpressionType::Error); + return CreateErrorExpr(memberRefExpr); } else if (elementCount == 1) { @@ -4844,7 +4912,10 @@ namespace Slang } else { - getSink()->diagnose(memberRefExpr, Diagnostics::unimplemented, "swizzle on vector of unknown size"); + if (!isRewriteMode()) + { + getSink()->diagnose(memberRefExpr, Diagnostics::unimplemented, "swizzle on vector of unknown size"); + } return CreateErrorExpr(memberRefExpr); } } @@ -4928,7 +4999,10 @@ namespace Slang // catch-all fail: - getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->name, baseType); + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::noMemberOfNameInType, expr->name, baseType); + } expr->Type = QualType(ExpressionType::Error); return expr; } @@ -4940,7 +5014,10 @@ namespace Slang if (!baseType->Equals(ExpressionType::Error.Ptr()) && expr->Type->Equals(ExpressionType::Error.Ptr())) { - getSink()->diagnose(expr, Diagnostics::typeHasNoPublicMemberOfName, baseType, expr->name); + if (!isRewriteMode()) + { + getSink()->diagnose(expr, Diagnostics::typeHasNoPublicMemberOfName, baseType, expr->name); + } } return expr; } -- cgit v1.2.3 From 6233f9b35f1901ca33c53ce37f9b1517e91e1d79 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Sat, 8 Jul 2017 17:04:31 -0700 Subject: Revise how hidden implicit casts are recognized. The old approach used an `isRewriter` flag in the emit logic, but I kind of need that flag to go away. Instead, I now how the semantic checking pass detect whether an implicitly-generated type cast is in rewriter code, and if so it uses the new `HiddenImplicitCastExpr` AST node. The emit logic then looks for that specific node and eliminates it. --- source/slang/check.cpp | 14 +++++++++++++- source/slang/emit.cpp | 17 +++++++---------- source/slang/expr-defs.h | 11 +++++++++++ source/slang/parser.cpp | 2 +- 4 files changed, 32 insertions(+), 12 deletions(-) (limited to 'source/slang/check.cpp') diff --git a/source/slang/check.cpp b/source/slang/check.cpp index f21f9480c..556f141c0 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -987,7 +987,19 @@ namespace Slang RefPtr toType, RefPtr fromExpr) { - auto castExpr = new ImplicitCastExpr(); + // In "rewrite" mode, we will generate a different syntax node + // to indicate that this type-cast was implicitly generated + // by the compiler, and shouldn't appear in the output code. + RefPtr castExpr; + if (isRewriteMode()) + { + castExpr = new HiddenImplicitCastExpr(); + } + else + { + castExpr = new ImplicitCastExpr(); + } + castExpr->Position = fromExpr->Position; castExpr->TargetType.type = toType; castExpr->Type = QualType(toType); diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index a1d95ca7e..a8c0083c1 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -2031,18 +2031,15 @@ struct EmitVisitor if(needClose) Emit(")"); } - void visitTypeCastExpressionSyntaxNode(TypeCastExpressionSyntaxNode* castExpr, ExprEmitArg const& arg) + void visitHiddenImplicitCastExpr(HiddenImplicitCastExpr* castExpr, ExprEmitArg const& arg) { - if (context->isRewrite) - { - if (dynamic_cast(castExpr)) - { - // This was an implicit cast, so don't try to output it - ExprVisitorWithArg::dispatch(castExpr->Expression, arg); - return; - } - } + // This was an implicit cast inserted in code parsed in "rewriter" mode, + // so we don't want to output it and change what the user's code looked like. + ExprVisitorWithArg::dispatch(castExpr->Expression, arg); + } + void visitTypeCastExpressionSyntaxNode(TypeCastExpressionSyntaxNode* castExpr, ExprEmitArg const& arg) + { bool needClose = false; switch(context->shared->target) { diff --git a/source/slang/expr-defs.h b/source/slang/expr-defs.h index 5ca6629b9..0dac324b9 100644 --- a/source/slang/expr-defs.h +++ b/source/slang/expr-defs.h @@ -91,14 +91,25 @@ SYNTAX_CLASS(DerefExpr, ExpressionSyntaxNode) SYNTAX_FIELD(RefPtr, base) END_SYNTAX_CLASS() +// Any operation that performs type-casting SYNTAX_CLASS(TypeCastExpressionSyntaxNode, ExpressionSyntaxNode) SYNTAX_FIELD(TypeExp, TargetType) SYNTAX_FIELD(RefPtr, Expression) END_SYNTAX_CLASS() +// An explicit type-cast that appear in the user's code with `(Type) expr` syntax +SYNTAX_CLASS(ExplicitCastExpr, TypeCastExpressionSyntaxNode) +END_SYNTAX_CLASS() + +// An implicit type-cast inserted during semantic checking SYNTAX_CLASS(ImplicitCastExpr, TypeCastExpressionSyntaxNode) END_SYNTAX_CLASS() +// An implicit type-cast that should also be hidden on output, +// because we don't want to mess with the user's code +SYNTAX_CLASS(HiddenImplicitCastExpr, ImplicitCastExpr) +END_SYNTAX_CLASS() + SIMPLE_SYNTAX_CLASS(SelectExpressionSyntaxNode, OperatorExpressionSyntaxNode) SIMPLE_SYNTAX_CLASS(GenericAppExpr, AppExprBase) diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index 2056bf809..0efc8cd77 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -3092,7 +3092,7 @@ namespace Slang if (peekTypeName(parser) && parser->LookAheadToken(TokenType::RParent, 1)) { - RefPtr tcexpr = new TypeCastExpressionSyntaxNode(); + RefPtr tcexpr = new ExplicitCastExpr(); parser->FillPosition(tcexpr.Ptr()); tcexpr->TargetType = parser->ParseTypeExp(); parser->ReadToken(TokenType::RParent); -- cgit v1.2.3 From 780a0bcd3724cad77cb65f931f111273776c9ca4 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Sat, 8 Jul 2017 17:47:31 -0700 Subject: Add back `UnparsedStmt` If the user doesn't use any `import` declarations, there is no reason to parse their code at all, so having the option of falling back to `UnparsedStmt` can potentially save us some headaches down the road. The new rule now is that if you have the "no checking" flag on, *and* the parser hasn't yet seen any `import` declarations, then it still used `UnparsedStmt` to avoid touching function bodies. Otherwise, I go ahead and parse function bodies, and assume I can rewrite any code I can semantically understand. --- source/slang/check.cpp | 5 +++++ source/slang/emit.cpp | 16 ++++++++++++++ source/slang/lower.cpp | 10 +++++++++ source/slang/parser.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ source/slang/stmt-defs.h | 7 ++++++ 5 files changed, 94 insertions(+) (limited to 'source/slang/check.cpp') diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 556f141c0..2b9abef90 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -1790,6 +1790,11 @@ namespace Slang checkStmt(stmt->NegativeStatement); } + void visitUnparsedStmt(UnparsedStmt*) + { + // Nothing to do + } + void visitEmptyStatementSyntaxNode(EmptyStatementSyntaxNode*) { // Nothing to do diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp index 24b0dd717..20b9856c5 100644 --- a/source/slang/emit.cpp +++ b/source/slang/emit.cpp @@ -2121,6 +2121,17 @@ struct EmitVisitor } } + void EmitUnparsedStmt(RefPtr stmt) + { + // TODO: actually emit the tokens that made up the statement... + Emit("{\n"); + for( auto& token : stmt->tokens ) + { + emitTokenWithLocation(token); + } + Emit("}\n"); + } + void EmitStmt(RefPtr stmt) { // Try to ensure that debugging can find the right location @@ -2139,6 +2150,11 @@ struct EmitVisitor } return; } + else if( auto unparsedStmt = stmt.As() ) + { + EmitUnparsedStmt(unparsedStmt); + return; + } else if (auto exprStmt = stmt.As()) { EmitExpr(exprStmt->Expression); diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp index 8a4b7a4b1..0d54faf0b 100644 --- a/source/slang/lower.cpp +++ b/source/slang/lower.cpp @@ -688,6 +688,16 @@ struct LoweringVisitor addStmt(loweredStmt); } + void visitUnparsedStmt(UnparsedStmt* stmt) + { + RefPtr loweredStmt = new UnparsedStmt(); + lowerStmtFields(loweredStmt, stmt); + + loweredStmt->tokens = stmt->tokens; + + addStmt(loweredStmt); + } + void visitCaseStmt(CaseStmt* stmt) { RefPtr loweredStmt = new CaseStmt(); diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp index 199275a2d..759fc0c20 100644 --- a/source/slang/parser.cpp +++ b/source/slang/parser.cpp @@ -44,6 +44,11 @@ namespace Slang String fileName; int genericDepth = 0; + // Have we seen any `import` declarations? If so, we need + // to parse function bodies completely, even if we are in + // "rewrite" mode. + bool haveSeenAnyImportDecls = false; + // Is the parser in a "recovering" state? // During recovery we don't emit additional errors, until we find // a token that we expected, when we exit recovery. @@ -802,6 +807,8 @@ namespace Slang static RefPtr parseImportDecl( Parser* parser) { + parser->haveSeenAnyImportDecls = true; + parser->ReadToken("__import"); auto decl = new ImportDecl(); @@ -842,6 +849,8 @@ namespace Slang static RefPtr parsePoundImportDecl( Parser* parser) { + parser->haveSeenAnyImportDecls = true; + Token importToken = parser->ReadToken(TokenType::PoundImport); auto decl = new ImportDecl(); @@ -2599,6 +2608,53 @@ namespace Slang RefPtr Parser::ParseBlockStatement() { + // If we are being asked not to check things *and* we haven't + // seen any `import` declarations yet, then we can safely assume + // that function bodies should be left as-is. + if( (translationUnit->compileFlags & SLANG_COMPILE_FLAG_NO_CHECKING) + && !haveSeenAnyImportDecls ) + { + // We have been asked to parse the input, but not attempt to understand it. + + // TODO: record start/end locations... + + List tokens; + + ReadToken(TokenType::LBrace); + + int depth = 1; + for( ;;) + { + switch( tokenReader.PeekTokenType() ) + { + case TokenType::EndOfFile: + goto done; + + case TokenType::RBrace: + depth--; + if(depth == 0) + goto done; + break; + + case TokenType::LBrace: + depth++; + break; + + default: + break; + } + + auto token = tokenReader.AdvanceToken(); + tokens.Add(token); + } + done: + ReadToken(TokenType::RBrace); + + RefPtr unparsedStmt = new UnparsedStmt(); + unparsedStmt->tokens = tokens; + return unparsedStmt; + } + RefPtr scopeDecl = new ScopeDecl(); RefPtr blockStatement = new BlockStmt(); blockStatement->scopeDecl = scopeDecl; diff --git a/source/slang/stmt-defs.h b/source/slang/stmt-defs.h index 15826abc4..9dea40fbf 100644 --- a/source/slang/stmt-defs.h +++ b/source/slang/stmt-defs.h @@ -16,6 +16,13 @@ SYNTAX_CLASS(BlockStmt, ScopeStmt) SYNTAX_FIELD(RefPtr, body); END_SYNTAX_CLASS() +// A statement that we aren't going to parse or check, because +// we want to let a downstream compiler handle any issues +SYNTAX_CLASS(UnparsedStmt, StatementSyntaxNode) + // The tokens that were contained between `{` and `}` + FIELD(List, tokens) +END_SYNTAX_CLASS() + SIMPLE_SYNTAX_CLASS(EmptyStatementSyntaxNode, StatementSyntaxNode) SIMPLE_SYNTAX_CLASS(DiscardStatementSyntaxNode, StatementSyntaxNode) -- cgit v1.2.3 From 767d47a842700653b8deffe82ccb3c85ad582c13 Mon Sep 17 00:00:00 2001 From: Tim Foley Date: Sat, 8 Jul 2017 18:13:53 -0700 Subject: Fix constant folding for `ParenExpr` Adding an explicit AST node for `(expr)` was a good change, but it broke constant folding because I forgot to handle it. --- source/slang/check.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source/slang/check.cpp') diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 2b9abef90..b87f7c6bc 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -2128,6 +2128,12 @@ namespace Slang RefPtr TryConstantFoldExpr( ExpressionSyntaxNode* expr) { + // Unwrap any "identity" expressions + while (auto parenExpr = dynamic_cast(expr)) + { + expr = parenExpr->base; + } + // TODO(tfoley): more serious constant folding here if (auto constExp = dynamic_cast(expr)) { -- cgit v1.2.3