From 786f48d32340c36a06865a333ff9066033b5b2bc Mon Sep 17 00:00:00 2001 From: Yong He Date: Fri, 12 Aug 2022 07:57:41 -0700 Subject: Fix logic of `is` operator. (#2359) --- source/slang/slang-ast-expr.h | 3 ++- source/slang/slang-check-expr.cpp | 23 ++++++++++++++--------- source/slang/slang-diagnostic-defs.h | 4 +--- source/slang/slang-language-server.cpp | 7 +++++++ source/slang/slang-lower-to-ir.cpp | 4 ++-- source/slang/slang-parser.cpp | 2 ++ 6 files changed, 28 insertions(+), 15 deletions(-) (limited to 'source/slang') diff --git a/source/slang/slang-ast-expr.h b/source/slang/slang-ast-expr.h index 6f10f2d82..828ca035f 100644 --- a/source/slang/slang-ast-expr.h +++ b/source/slang/slang-ast-expr.h @@ -316,7 +316,8 @@ class IsTypeExpr : public Expr // A witness showing that `typeExpr.type` is a subtype of `typeof(value)`. Val* witnessArg = nullptr; - bool isAlwaysTrue = false; + // non-null if evaluates to a constant. + BoolLiteralExpr* constantVal = nullptr; }; /// A `value as Type` expression that casts `value` to `Type` within type hierarchy. diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index cb75e3078..2ac02b978 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -1771,30 +1771,35 @@ namespace Slang { // Instead of returning a BoolLiteralExpr, we use a field to indicate this scenario, // so that the language server can still see the original syntax tree. - expr->isAlwaysTrue = true; + expr->constantVal = m_astBuilder->create(); + expr->constantVal->type = m_astBuilder->getBoolType(); + expr->constantVal->value = true; + expr->constantVal->loc = expr->loc; return expr; } // Otherwise, we need to ensure the target type is a subtype of value->type. - // For now we can only support the scenario where `expr->value` is an interface type. - if (!isInterfaceType(originalVal->type)) - { - getSink()->diagnose(expr, Diagnostics::isOperatorValueMustBeInterfaceType); - } expr->value = maybeOpenExistential(originalVal); expr->witnessArg = tryGetSubtypeWitness(expr->typeExpr.type, originalVal->type.type); if (expr->witnessArg) { + // For now we can only support the scenario where `expr->value` is an interface type. + if (!isInterfaceType(originalVal->type)) + { + getSink()->diagnose(expr, Diagnostics::isOperatorValueMustBeInterfaceType); + } return expr; } if (!as(expr->typeExpr.type) && !as(expr->value->type.type)) { - getSink()->diagnose(expr, Diagnostics::typeNotInTheSameHierarchy, expr->value->type.type, expr->typeExpr.type); + // The type is not in the same hierarchy, so we evaluate to false. + expr->constantVal = m_astBuilder->create(); + expr->constantVal->type = m_astBuilder->getBoolType(); + expr->constantVal->value = false; + expr->constantVal->loc = expr->loc; } - - expr->type = m_astBuilder->getErrorType(); return expr; } diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 54d81da7d..cbbb284cb 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -250,10 +250,8 @@ DIAGNOSTIC(30012, Error, noOverloadFoundForBinOperatorOnTypes, "no overload foun DIAGNOSTIC(30013, Error, subscriptNonArray, "no subscript operation found for type '$0'") DIAGNOSTIC(30014, Error, subscriptIndexNonInteger, "index expression must evaluate to int.") DIAGNOSTIC(30015, Error, undefinedIdentifier2, "undefined identifier '$0'.") -DIAGNOSTIC(30017, Error, componentNotAccessibleFromShader, "component '$0' is not accessible from shader '$1'.") -DIAGNOSTIC(30018, Error, typeNotInTheSameHierarchy, "as/is operator requires '$0' and '$1' to be in the same type hierarchy.") +DIAGNOSTIC(30018, Error, typeNotInTheSameHierarchy, "invalid use of 'as' operator: expression evaluates to '$0', which is not in the same type hierarchy as target type '$1'.") DIAGNOSTIC(30019, Error, typeMismatch, "expected an expression of type '$0', got '$1'") -DIAGNOSTIC(30020, Error, importOperatorReturnTypeMismatch, "import operator should return '$1', but the expression has type '$0''. do you forget 'project'?") DIAGNOSTIC(30021, Error, noApplicationFunction, "$0: no overload takes arguments ($1)") DIAGNOSTIC(30022, Error, invalidTypeCast, "invalid type cast between \"$0\" and \"$1\".") DIAGNOSTIC(30023, Error, typeHasNoPublicMemberOfName, "\"$0\" does not have public member \"$1\".") diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp index 768fee9e5..f209a4955 100644 --- a/source/slang/slang-language-server.cpp +++ b/source/slang/slang-language-server.cpp @@ -217,6 +217,13 @@ String getDeclSignatureString(DeclRef declRef, ASTBuilder* astBuilder) { sb << " = " << litExpr->token.getContent(); } + else if (auto isTypeDecl = as(varDecl->initExpr)) + { + if (isTypeDecl->constantVal) + { + sb << " = " << (isTypeDecl->constantVal->value ? "true" : "false"); + } + } } return printer.getString(); } diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp index c7fbfda77..81ea93f77 100644 --- a/source/slang/slang-lower-to-ir.cpp +++ b/source/slang/slang-lower-to-ir.cpp @@ -3966,9 +3966,9 @@ struct ExprLoweringVisitorBase : ExprVisitor LoweredValInfo visitIsTypeExpr(IsTypeExpr* expr) { - if (expr->isAlwaysTrue) + if (expr->constantVal) { - return LoweredValInfo::simple(getBuilder()->getBoolValue(true)); + return LoweredValInfo::simple(getBuilder()->getBoolValue(expr->constantVal->value)); } auto value = lowerLValueExpr(context, expr->value); auto type = lowerType(context, expr->type); diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 7447859c7..33f2e251b 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -4858,6 +4858,7 @@ namespace Slang isExpr->value = expr; parser->ReadToken(); isExpr->typeExpr = parser->ParseTypeExp(); + isExpr->loc = opToken.loc; expr = isExpr; continue; } @@ -4867,6 +4868,7 @@ namespace Slang asExpr->value = expr; parser->ReadToken(); asExpr->typeExpr = parser->ParseType(); + asExpr->loc = opToken.loc; expr = asExpr; continue; } -- cgit v1.2.3