summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/compiler-core/slang-doc-extractor.cpp5
-rw-r--r--source/slang/core.meta.slang82
-rw-r--r--source/slang/slang-ast-modifier.h6
-rw-r--r--source/slang/slang-ast-support-types.h14
-rw-r--r--source/slang/slang-check-conversion.cpp19
-rw-r--r--source/slang/slang-check-decl.cpp124
-rw-r--r--source/slang/slang-check-impl.h12
-rw-r--r--source/slang/slang-doc-ast.cpp4
-rw-r--r--source/slang/slang-language-server.cpp77
-rw-r--r--tests/diagnostics/enum-implicit-conversion.slang30
-rw-r--r--tests/diagnostics/enum-implicit-conversion.slang.expected26
-rw-r--r--tests/language-feature/enums/enum-bit-ops.slang32
-rw-r--r--tests/language-server/ordinary-comment-hover-info.slang.expected.txt2
-rw-r--r--tests/language-server/robustness-2.slang.expected.txt2
14 files changed, 298 insertions, 137 deletions
diff --git a/source/compiler-core/slang-doc-extractor.cpp b/source/compiler-core/slang-doc-extractor.cpp
index ffbfc9904..9a625f3e0 100644
--- a/source/compiler-core/slang-doc-extractor.cpp
+++ b/source/compiler-core/slang-doc-extractor.cpp
@@ -766,7 +766,10 @@ SlangResult DocMarkupExtractor::extract(const SearchItemInput* inputs, Index inp
// Find the new view
sourceView = sourceManager->findSourceView(loc);
if (!sourceView)
- return SLANG_FAIL;
+ {
+ entry.searchStyle = SearchStyle::None;
+ continue;
+ }
// We want only one view per SourceFile
SourceFile* sourceFile = sourceView->getSourceFile();
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index 583dd5923..dcb1a159b 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -76,8 +76,13 @@ syntax __extern_cpp : ExternCppModifier;
interface IComparable
{
+ __builtin_requirement($( (int)BuiltinRequirementKind::Equals))
bool equals(This other);
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::LessThan))
bool lessThan(This other);
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::LessThanOrEquals))
bool lessThanOrEquals(This other);
}
@@ -107,15 +112,34 @@ interface IArithmetic : IComparable
interface ILogical : IComparable
{
+ __builtin_requirement($( (int)BuiltinRequirementKind::Shl) )
This shl(int value);
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::Shr) )
This shr(int value);
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::BitAnd) )
This bitAnd(This other);
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::BitOr) )
This bitOr(This other);
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::BitXor) )
This bitXor(This other);
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::BitNot) )
This bitNot();
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::And) )
This and(This other);
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::Or) )
This or(This other);
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::Not) )
This not();
+
+ __builtin_requirement($( (int)BuiltinRequirementKind::InitLogicalFromInt) )
__init(int val);
}
@@ -336,66 +360,19 @@ interface __BuiltinFloatingPointType : __BuiltinRealType, IFloat
// A type resulting from an `enum` declaration.
[builtin]
__magic_type(EnumTypeType)
-interface __EnumType
+interface __EnumType : ILogical
{
// The type of tags for this `enum`
//
// Note: using `__Tag` instead of `Tag` to avoid any
// conflict if a user had an `enum` case called `Tag`
associatedtype __Tag : __BuiltinIntegerType;
-};
-// Use an extension to declare that every `enum` type
-// inherits an initializer based on the tag type.
-//
-// Note: there is an important and subtle point here.
-// If we declared these initializers inside the `interface`
-// declaration above, then they would implicitly be
-// *requirements* of the `__EnumType` interface, and any
-// type that declares conformance to it would need to
-// provide implementations. That would put the onus on
-// the semantic checker to synthesize such initializers
-// when conforming an `enum` type to `__EnumType` (just
-// as it currently synthesizes the `__Tag` requirement.
-// Putting the declaration in an `extension` makes them
-// concrete declerations rather than interface requirements.
-// (Admittedly, they are "concrete" declarations with
-// no bodies, because currently all initializers are
-// assumed to be intrinsics).
-//
-// TODO: It might be more accurate to express this as:
-//
-// __generic<T:__EnumType> extension T { ... }
-//
-// That alternative would express an extension of every
-// type that conforms to `__EnumType`, rather than an
-// extension of `__EnumType` itself. The distinction
-// is subtle, and unfortunately not one the Slang type
-// checker is equiped to handle right now. For now we
-// will stick with the syntax that actually works, even
-// if it might be the less technically correct one.
-//
-//
-extension __EnumType
-{
- // TODO: this should be a single initializer using
- // the `__Tag` associated type from the `__EnumType`
- // interface, but right now the scoping for looking
- // up that type isn't working right.
- //
- __intrinsic_op($(kIROp_IntCast))
- __init(int value);
- __intrinsic_op($(kIROp_IntCast))
- __init(uint value);
-}
-
-// A type resulting from an `enum` declaration
-// with the `[flags]` attribute.
-[builtin]
-interface __FlagsEnumType : __EnumType
-{
+ __builtin_requirement($( (int)BuiltinRequirementKind::InitLogicalFromInt) )
+ __init(__Tag value);
};
+
interface IArray<T>
{
int getCount();
@@ -2404,6 +2381,9 @@ attribute_syntax [disable_array_flattening] : DisableArrayFlatteningAttribute;
__attributeTarget(EnumDecl)
attribute_syntax [UnscopedEnum] : UnscopedEnumAttribute;
+__attributeTarget(EnumDecl)
+attribute_syntax[Flags] : FlagsAttribute;
+
// Statement Attributes
__attributeTarget(LoopStmt)
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h
index 4ccca36ea..376307260 100644
--- a/source/slang/slang-ast-modifier.h
+++ b/source/slang/slang-ast-modifier.h
@@ -717,6 +717,12 @@ class UnscopedEnumAttribute : public Attribute
SLANG_AST_CLASS(UnscopedEnumAttribute)
};
+ // Marks a enum to have `flags` semantics, where each enum case is a bitfield.
+class FlagsAttribute : public Attribute
+{
+ SLANG_AST_CLASS(FlagsAttribute);
+};
+
// [[vk_push_constant]] [[push_constant]]
class PushConstantAttribute : public Attribute
{
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index 93fc3365d..4b3a6cc9f 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -1606,6 +1606,20 @@ namespace Slang
DZeroFunc, ///< The `IDifferentiable.dzero` function requirement
DAddFunc, ///< The `IDifferentiable.dadd` function requirement
DMulFunc, ///< The `IDifferentiable.dmul` function requirement
+
+ InitLogicalFromInt, ///< The `ILogical.__init` mtehod.
+ Equals, ///< The `ILogical.equals` mtehod.
+ LessThan, ///< The `ILogical.lessThan` mtehod.
+ LessThanOrEquals, ///< The `ILogical.lessThanOrEquals` mtehod.
+ Shl, ///< The `ILogical.shl` mtehod.
+ Shr, ///< The `ILogical.shr` mtehod.
+ BitAnd, ///< The `ILogical.bitAnd` mtehod.
+ BitOr, ///< The `ILogical.bitOr` mtehod.
+ BitXor, ///< The `ILogical.bitXor` mtehod.
+ BitNot, ///< The `ILogical.bitNot` mtehod.
+ And, ///< The `ILogical.and` mtehod.
+ Or, ///< The `ILogical.or` mtehod.
+ Not, ///< The `ILogical.not` mtehod.
};
enum class FunctionDifferentiableLevel
diff --git a/source/slang/slang-check-conversion.cpp b/source/slang/slang-check-conversion.cpp
index e55a88077..7dcc8975c 100644
--- a/source/slang/slang-check-conversion.cpp
+++ b/source/slang/slang-check-conversion.cpp
@@ -894,6 +894,25 @@ namespace Slang
}
return true;
}
+
+ // A enum type can be converted into its underlying tag type.
+ if (auto enumDecl = isEnumType(fromType))
+ {
+ Type* tagType = enumDecl->tagType;
+ if (tagType == toType)
+ {
+ if (outCost)
+ {
+ *outCost = kConversionCost_RankPromotion;
+ }
+ if (outToExpr)
+ {
+ *outToExpr = fromExpr;
+ }
+ return true;
+ }
+ }
+
// matrix type with different layouts are convertible
if (auto fromMatrixType = as<MatrixExpressionType>(fromType))
{
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 78eccbc8c..07c8b0cba 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -1335,6 +1335,15 @@ namespace Slang
return arrayType->isUnsized();
}
+ EnumDecl* isEnumType(Type* type)
+ {
+ if (auto declRefType = as<DeclRefType>(type))
+ {
+ return as<EnumDecl>(declRefType->getDeclRef().getDecl());
+ }
+ return nullptr;
+ }
+
bool SemanticsVisitor::shouldSkipChecking(Decl* decl, DeclCheckState state)
{
if (state < DeclCheckState::DefinitionChecked)
@@ -3591,13 +3600,14 @@ namespace Slang
}
}
- FuncDecl* SemanticsVisitor::synthesizeMethodSignatureForRequirementWitness(
+ FunctionDeclBase* SemanticsVisitor::synthesizeMethodSignatureForRequirementWitness(
ConformanceCheckingContext* context,
- DeclRef<FuncDecl> requiredMemberDeclRef,
+ DeclRef<FunctionDeclBase> requiredMemberDeclRef,
List<Expr*>& synArgs,
ThisExpr*& synThis)
{
- auto synFuncDecl = m_astBuilder->create<FuncDecl>();
+ FunctionDeclBase* synFuncDecl = as<FunctionDeclBase>(m_astBuilder->createByNodeType(requiredMemberDeclRef.getDecl()->astNodeType));
+ SLANG_ASSERT(synFuncDecl);
synFuncDecl->ownedScope = m_astBuilder->create<Scope>();
synFuncDecl->ownedScope->containerDecl = synFuncDecl;
synFuncDecl->ownedScope->parent = getScope(context->parentDecl);
@@ -3913,6 +3923,14 @@ namespace Slang
{
SLANG_UNUSED(satisfyingMemberLookupResult);
+ if (as<EnumDecl>(context->parentDecl))
+ {
+ if (auto builtinRequirement = requiredMemberDeclRef.getDecl()->findModifier<BuiltinRequirementModifier>())
+ {
+ return trySynthesizeEnumTypeMethodRequirementWitness(context, requiredMemberDeclRef, witnessTable, builtinRequirement->kind);
+ }
+ }
+
bool isInWrapperType = isWrapperTypeDecl(context->parentDecl);
if (!isInWrapperType)
{
@@ -4593,6 +4611,21 @@ namespace Slang
requiredFuncDeclRef,
witnessTable,
SynthesisPattern::AllInductive);
+ case BuiltinRequirementKind::And:
+ case BuiltinRequirementKind::Or:
+ case BuiltinRequirementKind::Not:
+ case BuiltinRequirementKind::BitAnd:
+ case BuiltinRequirementKind::BitNot:
+ case BuiltinRequirementKind::BitOr:
+ case BuiltinRequirementKind::BitXor:
+ case BuiltinRequirementKind::Shl:
+ case BuiltinRequirementKind::Shr:
+ case BuiltinRequirementKind::Equals:
+ case BuiltinRequirementKind::LessThan:
+ case BuiltinRequirementKind::LessThanOrEquals:
+ if (isEnumType(context->conformingType))
+ return trySynthesizeEnumTypeMethodRequirementWitness(context, requiredFuncDeclRef, witnessTable, builtinAttr->kind);
+ break;
}
}
return false;
@@ -4739,6 +4772,70 @@ namespace Slang
return synth.emitAssignStmt(leftValue, synth.emitInvokeExpr(callee, _Move(args)));
}
+ bool SemanticsVisitor::trySynthesizeEnumTypeMethodRequirementWitness(ConformanceCheckingContext* context,
+ DeclRef<FunctionDeclBase> funcDeclRef,
+ RefPtr<WitnessTable> witnessTable,
+ BuiltinRequirementKind requirementKind)
+ {
+ List<Expr*> synArgs;
+ ThisExpr* synThis = nullptr;
+ auto synFunc = synthesizeMethodSignatureForRequirementWitness(
+ context, funcDeclRef, synArgs, synThis);
+ auto intrinsicOpModifier = getASTBuilder()->create<IntrinsicOpModifier>();
+ switch (requirementKind)
+ {
+ case BuiltinRequirementKind::And:
+ intrinsicOpModifier->op = kIROp_And;
+ break;
+ case BuiltinRequirementKind::Or:
+ intrinsicOpModifier->op = kIROp_Or;
+ break;
+ case BuiltinRequirementKind::Not:
+ intrinsicOpModifier->op = kIROp_Not;
+ break;
+ case BuiltinRequirementKind::BitAnd:
+ intrinsicOpModifier->op = kIROp_BitAnd;
+ break;
+ case BuiltinRequirementKind::BitNot:
+ intrinsicOpModifier->op = kIROp_BitNot;
+ break;
+ case BuiltinRequirementKind::BitOr:
+ intrinsicOpModifier->op = kIROp_BitOr;
+ break;
+ case BuiltinRequirementKind::BitXor:
+ intrinsicOpModifier->op = kIROp_BitXor;
+ break;
+ case BuiltinRequirementKind::Shl:
+ intrinsicOpModifier->op = kIROp_Lsh;
+ break;
+ case BuiltinRequirementKind::Shr:
+ intrinsicOpModifier->op = kIROp_Rsh;
+ break;
+ case BuiltinRequirementKind::Equals:
+ intrinsicOpModifier->op = kIROp_Eql;
+ break;
+ case BuiltinRequirementKind::LessThan:
+ intrinsicOpModifier->op = kIROp_Less;
+ break;
+ case BuiltinRequirementKind::LessThanOrEquals:
+ intrinsicOpModifier->op = kIROp_Leq;
+ break;
+ case BuiltinRequirementKind::InitLogicalFromInt:
+ intrinsicOpModifier->op = kIROp_IntCast;
+ break;
+ default:
+ SLANG_ASSERT("unknown builtin requirement kind.");
+ }
+ synFunc->parentDecl = context->parentDecl;
+ synFunc->loc = context->parentDecl->closingSourceLoc;
+ synFunc->nameAndLoc.loc = synFunc->loc;
+ context->parentDecl->members.add(synFunc);
+ context->parentDecl->invalidateMemberDictionary();
+ addModifier(synFunc, intrinsicOpModifier);
+ witnessTable->add(funcDeclRef.getDecl(), RequirementWitness(m_astBuilder->getDirectDeclRef(synFunc)));
+ return true;
+ }
+
bool SemanticsVisitor::trySynthesizeDifferentialMethodRequirementWitness(
ConformanceCheckingContext* context,
DeclRef<Decl> requirementDeclRef,
@@ -4801,8 +4898,8 @@ namespace Slang
}
else if (auto funcDeclRef = requirementDeclRef.as<FuncDecl>())
{
- synFunc = synthesizeMethodSignatureForRequirementWitness(
- context, funcDeclRef, synArgs, synThis);
+ synFunc = as<FuncDecl>(synthesizeMethodSignatureForRequirementWitness(
+ context, funcDeclRef, synArgs, synThis));
}
SLANG_ASSERT(synFunc);
@@ -6083,6 +6180,8 @@ namespace Slang
auto tagType = decl->tagType;
+ auto isEnumFlags = decl->hasModifier<FlagsAttribute>();
+
// Check the enum cases in order.
for(auto caseDecl : decl->getMembersOfType<EnumCaseDecl>())
{
@@ -6102,7 +6201,7 @@ namespace Slang
// For any enum case that didn't provide an explicit
// tag value, derived an appropriate tag value.
- IntegerLiteralValue defaultTag = 0;
+ IntegerLiteralValue defaultTag = isEnumFlags ? 1 : 0;
for(auto caseDecl : decl->getMembersOfType<EnumCaseDecl>())
{
if(auto explicitTagValExpr = caseDecl->tagExpr)
@@ -6146,10 +6245,15 @@ namespace Slang
// Default tag for the next case will be one more than
// for the most recent case.
//
- // TODO: We might consider adding a `[flags]` attribute
- // that modifies this behavior to be `defaultTagForCase <<= 1`.
- //
- defaultTag++;
+ if (!isEnumFlags)
+ defaultTag++;
+ else
+ {
+ if (defaultTag == 0)
+ defaultTag = 1;
+ else
+ defaultTag <<= 1;
+ }
}
}
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 945618f36..002ef1f71 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -1612,9 +1612,9 @@ namespace Slang
CallableDecl* synthesized,
List<Expr*>& synArgs);
- FuncDecl* synthesizeMethodSignatureForRequirementWitness(
+ FunctionDeclBase* synthesizeMethodSignatureForRequirementWitness(
ConformanceCheckingContext* context,
- DeclRef<FuncDecl> requiredMemberDeclRef,
+ DeclRef<FunctionDeclBase> requiredMemberDeclRef,
List<Expr*>& synArgs,
ThisExpr*& synThis);
@@ -1729,6 +1729,12 @@ namespace Slang
DeclRef<AssocTypeDecl> requirementDeclRef,
RefPtr<WitnessTable> witnessTable);
+ /// Attempt to synthesize function requirements for enum types to make them conform to `ILogical`.
+ bool trySynthesizeEnumTypeMethodRequirementWitness(ConformanceCheckingContext* context,
+ DeclRef<FunctionDeclBase> requirementDeclRef,
+ RefPtr<WitnessTable> witnessTable,
+ BuiltinRequirementKind requirementKind);
+
struct DifferentiableMemberInfo
{
Decl* memberDecl;
@@ -2751,6 +2757,8 @@ namespace Slang
bool isUnsizedArrayType(Type* type);
+ EnumDecl* isEnumType(Type* type);
+
DeclVisibility getDeclVisibility(Decl* decl);
void diagnoseCapabilityProvenance(DiagnosticSink* sink, Decl* decl, CapabilityAtom missingAtom);
diff --git a/source/slang/slang-doc-ast.cpp b/source/slang/slang-doc-ast.cpp
index dfe3b321c..172f31b32 100644
--- a/source/slang/slang-doc-ast.cpp
+++ b/source/slang/slang-doc-ast.cpp
@@ -107,6 +107,10 @@ SlangResult ASTMarkupUtil::extract(ModuleDecl* moduleDecl, SourceManager* source
SLANG_ASSERT(item.sourceLoc.isValid());
item.searchStyle = getSearchStyle(decl);
+
+ // Don't generate documentation for synthesized members.
+ if (getText(decl->getName()).startsWith("$__syn"))
+ item.searchStyle = DocMarkupExtractor::SearchStyle::None;
}
DocMarkupExtractor extractor;
diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp
index 9cfef50a0..8f71666dd 100644
--- a/source/slang/slang-language-server.cpp
+++ b/source/slang/slang-language-server.cpp
@@ -291,51 +291,62 @@ String getDeclSignatureString(DeclRef<Decl> declRef, WorkspaceVersion* version)
ASTPrinter::OptionFlag::SimplifiedBuiltinType);
printer.getStringBuilder() << getDeclKindString(declRef);
printer.addDeclSignature(declRef);
- if (auto varDecl = as<VarDeclBase>(declRef.getDecl()))
- {
- auto& sb = printer.getStringBuilder();
- if (!varDecl->findModifier<ConstModifier>() && !as<LetDecl>(declRef.getDecl()))
- return printer.getString();
-
- if (auto litExpr = as<LiteralExpr>(varDecl->initExpr))
- {
- sb << " = " << litExpr->token.getContent();
- }
- else if (auto isTypeDecl = as<IsTypeExpr>(varDecl->initExpr))
+ auto printInitExpr = [&](Module* module, Type* declType, Expr* initExpr)
{
- if (isTypeDecl->constantVal)
+ auto& sb = printer.getStringBuilder();
+
+ if (auto litExpr = as<LiteralExpr>(initExpr))
{
- sb << " = " << (isTypeDecl->constantVal->value ? "true" : "false");
+ if (litExpr->token.type != TokenType::Unknown)
+ sb << " = " << litExpr->token.getContent();
+ else if (auto intLit = as<IntegerLiteralExpr>(litExpr))
+ sb << " = " << intLit->value;
}
- }
- else if (varDecl->initExpr)
- {
- DiagnosticSink sink;
- SharedSemanticsContext semanticContext(version->linkage, getModule(varDecl), &sink);
- SemanticsVisitor semanticsVisitor(&semanticContext);
- if (auto intVal = semanticsVisitor.tryFoldIntegerConstantExpression(
- declRef.substitute(version->linkage->getASTBuilder(), varDecl->initExpr),
- SemanticsVisitor::ConstantFoldingKind::LinkTime, nullptr))
+ else if (auto isTypeDecl = as<IsTypeExpr>(initExpr))
{
- if (auto constantInt = as<ConstantIntVal>(intVal))
+ if (isTypeDecl->constantVal)
{
- sb << " = ";
- if (isBoolType(varDecl->getType()))
+ sb << " = " << (isTypeDecl->constantVal->value ? "true" : "false");
+ }
+ }
+ else if (initExpr)
+ {
+ DiagnosticSink sink;
+ SharedSemanticsContext semanticContext(version->linkage, module, &sink);
+ SemanticsVisitor semanticsVisitor(&semanticContext);
+ if (auto intVal = semanticsVisitor.tryFoldIntegerConstantExpression(
+ declRef.substitute(version->linkage->getASTBuilder(), initExpr),
+ SemanticsVisitor::ConstantFoldingKind::LinkTime, nullptr))
+ {
+ if (auto constantInt = as<ConstantIntVal>(intVal))
{
- sb << (constantInt->getValue() ? "true" : "false");
+ sb << " = ";
+ if (isBoolType(declType))
+ {
+ sb << (constantInt->getValue() ? "true" : "false");
+ }
+ else
+ {
+ sb << constantInt->getValue();
+ }
}
else
{
- sb << constantInt->getValue();
+ sb << " = ";
+ intVal->toText(sb);
}
}
- else
- {
- sb << " = ";
- intVal->toText(sb);
- }
}
- }
+ };
+ if (auto varDecl = as<VarDeclBase>(declRef.getDecl()))
+ {
+ if (!varDecl->findModifier<ConstModifier>() && !as<LetDecl>(declRef.getDecl()))
+ return printer.getString();
+ printInitExpr(getModule(varDecl), varDecl->type, varDecl->initExpr);
+ }
+ else if (auto enumCase = as<EnumCaseDecl>(declRef.getDecl()))
+ {
+ printInitExpr(getModule(enumCase), nullptr, enumCase->tagExpr);
}
return printer.getString();
}
diff --git a/tests/diagnostics/enum-implicit-conversion.slang b/tests/diagnostics/enum-implicit-conversion.slang
index fc4757f7e..51082183e 100644
--- a/tests/diagnostics/enum-implicit-conversion.slang
+++ b/tests/diagnostics/enum-implicit-conversion.slang
@@ -1,6 +1,6 @@
// enum-implicit-conversion.slang
-//DIAGNOSTIC_TEST:SIMPLE:
+//DIAGNOSTIC_TEST:SIMPLE(filecheck=CHECK):
// Confirm that suitable error messages are
// generated for code that relies on implicit
@@ -21,28 +21,34 @@ int bar(Color x) { return int(x) * 256; }
int bar(int x) { return x * 256 * 256; }
int bar(uint x) { return x * 256 * 256 * 16; }
+int baz(Color x) { return (int)x; }
int test(int val)
{
// Implicit conversion from `int` to `enum` isn't allowed.
+ // CHECK: ([[# @LINE+1]]): error
Color c = val;
- // TODO: explicit conversion to `enum` type should be allowed.
-// Color cc = Color(val);
-
+ // Implicit cast from enum to int types other than the tag type is not allowed.
+ // CHECK: ([[# @LINE+1]]): error
+ uint y = c;
- // Implicit converion from `enum` to `int` isn't allowed.
+ // Call that expects implicit conversion from int to enum shouldn't be allowed.
+ // CHECK: ([[# @LINE+1]]): error
+ int z = baz(5);
+
+ // CHECK-NOT: error
+
+ // Call that has an explicit overload on `enum` type should succeed.
+ int zz = bar(c);
+
+ Color cc = Color(val);
+
+ // Implicit converion from `enum` to `int` is allowed.
int x = c;
- uint y = c;
// Explicit converion is allowed.
int xx = int(c);
uint yy = uint(c);
- // Call that expects implicit conversion should fail.
- int z = foo(c);
-
- // Call that has an explicit overload on `enum` type should succeed.
- int zz = bar(c);
-
return x + y + z;
}
diff --git a/tests/diagnostics/enum-implicit-conversion.slang.expected b/tests/diagnostics/enum-implicit-conversion.slang.expected
deleted file mode 100644
index 376dab7e6..000000000
--- a/tests/diagnostics/enum-implicit-conversion.slang.expected
+++ /dev/null
@@ -1,26 +0,0 @@
-result code = -1
-standard error = {
-tests/diagnostics/enum-implicit-conversion.slang(27): error 30019: expected an expression of type 'Color', got 'int'
- Color c = val;
- ^~~
-tests/diagnostics/enum-implicit-conversion.slang(27): note: explicit conversion from 'int' to 'Color' is possible
-tests/diagnostics/enum-implicit-conversion.slang(34): error 30019: expected an expression of type 'int', got 'Color'
- int x = c;
- ^
-tests/diagnostics/enum-implicit-conversion.slang(34): note: explicit conversion from 'Color' to 'int' is possible
-tests/diagnostics/enum-implicit-conversion.slang(35): error 30019: expected an expression of type 'uint', got 'Color'
- uint y = c;
- ^
-tests/diagnostics/enum-implicit-conversion.slang(35): note: explicit conversion from 'Color' to 'uint' is possible
-tests/diagnostics/enum-implicit-conversion.slang(42): error 39999: ambiguous call to 'foo' with arguments of type (Color)
- int z = foo(c);
- ^
-tests/diagnostics/enum-implicit-conversion.slang(18): note 39999: candidate: func foo(uint) -> int
-int foo(uint x) { return x * 256 * 16; }
- ^~~
-tests/diagnostics/enum-implicit-conversion.slang(17): note 39999: candidate: func foo(int) -> int
-int foo(int x) { return x * 16; }
- ^~~
-}
-standard output = {
-}
diff --git a/tests/language-feature/enums/enum-bit-ops.slang b/tests/language-feature/enums/enum-bit-ops.slang
new file mode 100644
index 000000000..abffe8dee
--- /dev/null
+++ b/tests/language-feature/enums/enum-bit-ops.slang
@@ -0,0 +1,32 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -shaderobj
+
+[Flags]
+enum MyFlags
+{
+ Zero = 0,
+ BitOne, // = 1
+ BitTwo, // = 2
+ BitThree // = 4
+}
+
+bool test(MyFlags f1)
+{
+ return (f1 & MyFlags.BitTwo) != 0;
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+[numthreads(1, 1, 1)]
+void computeMain(int3 dispatchThreadID: SV_DispatchThreadID)
+{
+ int outVal = test(MyFlags.BitOne | MyFlags.BitTwo) ? 1 : 0;
+ // CHECK: 1
+ outputBuffer[0] = outVal;
+ // CHECK: 4
+ outputBuffer[1] = (int)MyFlags.BitThree;
+ // CHECK: 0
+ outputBuffer[2] = test(MyFlags.BitOne | MyFlags.BitThree) ? 1 : 0;
+ // CHECK: 8
+ outputBuffer[3] = MyFlags(8);
+}
diff --git a/tests/language-server/ordinary-comment-hover-info.slang.expected.txt b/tests/language-server/ordinary-comment-hover-info.slang.expected.txt
index 72b83c696..8c3a10487 100644
--- a/tests/language-server/ordinary-comment-hover-info.slang.expected.txt
+++ b/tests/language-server/ordinary-comment-hover-info.slang.expected.txt
@@ -25,7 +25,7 @@ func main() -> void
range: 19,3 - 19,8
content:
```
-E E.Green
+E E.Green = 1
```
#5 green color
diff --git a/tests/language-server/robustness-2.slang.expected.txt b/tests/language-server/robustness-2.slang.expected.txt
index 346f637c6..8e3b89c59 100644
--- a/tests/language-server/robustness-2.slang.expected.txt
+++ b/tests/language-server/robustness-2.slang.expected.txt
@@ -2,7 +2,7 @@
range: 14,4 - 14,7
content:
```
-Kind Kind.Foo
+Kind Kind.Foo = 0
```
HOVER:15,6