summaryrefslogtreecommitdiff
path: root/source/slang/slang-check-expr.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2022-08-10 14:11:27 -0700
committerGitHub <noreply@github.com>2022-08-10 14:11:27 -0700
commit88f04c29244af23c1cdd472d8d1ae3e5a650494e (patch)
tree398e55440e8f7ad157d15b2b75d9887236eaa126 /source/slang/slang-check-expr.cpp
parentfcdb4629c4c3dd2931eaa88b96b668d914c4519c (diff)
`is` and `as` operator and `Optional<T>`. (#2355)
* `is` and `as` operator and `Optional<T>`. * Fix. Co-authored-by: Yong He <yhe@nvidia.com>
Diffstat (limited to 'source/slang/slang-check-expr.cpp')
-rw-r--r--source/slang/slang-check-expr.cpp84
1 files changed, 84 insertions, 0 deletions
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index a787af211..714eba9a3 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -1753,6 +1753,90 @@ namespace Slang
return expr;
}
+ Expr* SemanticsExprVisitor::visitIsTypeExpr(IsTypeExpr* expr)
+ {
+ expr->typeExpr = CheckProperType(expr->typeExpr);
+ auto originalVal = CheckTerm(expr->value);
+ expr->type = m_astBuilder->getBoolType();
+ expr->value = originalVal;
+
+ // If value is a subtype of `type`, then this expr is always true.
+ if (isDeclaredSubtype(expr->value->type.type, expr->typeExpr.type))
+ {
+ // 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;
+ 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)
+ {
+ return expr;
+ }
+
+ if (!as<ErrorType>(expr->typeExpr.type) && !as<ErrorType>(expr->value->type.type))
+ {
+ getSink()->diagnose(expr, Diagnostics::typeNotInTheSameHierarchy, expr->value->type.type, expr->typeExpr.type);
+ }
+
+ expr->type = m_astBuilder->getErrorType();
+ return expr;
+ }
+
+ Expr* SemanticsExprVisitor::visitAsTypeExpr(AsTypeExpr* expr)
+ {
+ TypeExp typeExpr;
+ typeExpr.exp = expr->typeExpr;
+ typeExpr = CheckProperType(typeExpr);
+ expr->value = CheckTerm(expr->value);
+ auto optType = m_astBuilder->getOptionalType(typeExpr.type);
+ expr->type = optType;
+
+ // If value is a subtype of `type`, then this expr is equivalent to a CastToSuperTypeExpr.
+ if (auto witness = tryGetSubtypeWitness(expr->value->type.type, typeExpr.type))
+ {
+ auto castToSuperType = createCastToSuperTypeExpr(typeExpr.type, expr->value, witness);
+ auto makeOptional = m_astBuilder->create<MakeOptionalExpr>();
+ makeOptional->loc = expr->loc;
+ makeOptional->type = optType;
+ makeOptional->value = castToSuperType;
+ makeOptional->typeExpr = typeExpr.exp;
+ return makeOptional;
+ }
+
+ // For now we can only support the scenario where `expr->value` is an interface type.
+ if (!isInterfaceType(expr->value->type))
+ {
+ getSink()->diagnose(expr, Diagnostics::isOperatorValueMustBeInterfaceType);
+ }
+
+ expr->typeExpr = typeExpr.exp;
+ expr->witnessArg = tryGetSubtypeWitness(typeExpr.type, expr->value->type.type);
+ if (expr->witnessArg)
+ {
+ expr->value = maybeOpenExistential(expr->value);
+ return expr;
+ }
+
+ if (!as<ErrorType>(typeExpr.type) && !as<ErrorType>(expr->value->type.type))
+ {
+ getSink()->diagnose(expr, Diagnostics::typeNotInTheSameHierarchy, expr->value->type.type, typeExpr.type);
+ }
+
+ expr->type = m_astBuilder->getErrorType();
+
+ return expr;
+ }
+
Expr* SemanticsVisitor::MaybeDereference(Expr* inExpr)
{
Expr* expr = inExpr;