diff options
| author | Yong He <yonghe@outlook.com> | 2022-08-10 14:11:27 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-10 14:11:27 -0700 |
| commit | 88f04c29244af23c1cdd472d8d1ae3e5a650494e (patch) | |
| tree | 398e55440e8f7ad157d15b2b75d9887236eaa126 /source/slang/slang-check-expr.cpp | |
| parent | fcdb4629c4c3dd2931eaa88b96b668d914c4519c (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.cpp | 84 |
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; |
