From bfac247ff2489a1f7fb9766674a6ed25a48a493b Mon Sep 17 00:00:00 2001 From: Jay Kwak <82421531+jkwak-work@users.noreply.github.com> Date: Sun, 8 Jun 2025 12:54:52 -0700 Subject: Fix interface types as RHS of is/as operators (#7234) Added error checking to reject interface types as the right-hand side of is and as operators. Enhanced semantic analysis with new diagnostic 30301 and comprehensive test coverage. --- source/slang/slang-check-expr.cpp | 16 +++++ source/slang/slang-diagnostic-defs.h | 8 +++ .../language-feature/interface-as-rhs-error.slang | 73 ++++++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 tests/language-feature/interface-as-rhs-error.slang diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp index 66c2f9796..f4c8cd847 100644 --- a/source/slang/slang-check-expr.cpp +++ b/source/slang/slang-check-expr.cpp @@ -4065,6 +4065,13 @@ Expr* SemanticsExprVisitor::visitIsTypeExpr(IsTypeExpr* expr) expr->type = m_astBuilder->getBoolType(); expr->value = originalVal; + // Check if the right-hand side type is an interface type + if (isInterfaceType(expr->typeExpr.type)) + { + getSink()->diagnose(expr, Diagnostics::isAsOperatorCannotUseInterfaceAsRHS); + return expr; + } + auto valueType = expr->value->type.type; if (auto typeType = as(valueType)) valueType = typeType->getType(); @@ -4103,6 +4110,15 @@ Expr* SemanticsExprVisitor::visitAsTypeExpr(AsTypeExpr* expr) TypeExp typeExpr; typeExpr.exp = expr->typeExpr; typeExpr = CheckProperType(typeExpr); + + // Check if the right-hand side type is an interface type + if (isInterfaceType(typeExpr.type)) + { + getSink()->diagnose(expr, Diagnostics::isAsOperatorCannotUseInterfaceAsRHS); + expr->type = m_astBuilder->getErrorType(); + return expr; + } + expr->value = CheckTerm(expr->value); auto optType = m_astBuilder->getOptionalType(typeExpr.type); expr->type = optType; diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index bef32e20e..f4741ab04 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -842,7 +842,15 @@ DIAGNOSTIC( isOperatorValueMustBeInterfaceType, "'is'/'as' operator requires an interface-typed expression.") +DIAGNOSTIC( + 30301, + Error, + isAsOperatorCannotUseInterfaceAsRHS, + "'is' and 'as' operators do not support interface types as the right-hand side. Use a concrete " + "type instead.") + DIAGNOSTIC(33070, Error, expectedFunction, "expected a function, got '$0'") + DIAGNOSTIC(33071, Error, expectedAStringLiteral, "expected a string literal") // `dyn` and `some` errors diff --git a/tests/language-feature/interface-as-rhs-error.slang b/tests/language-feature/interface-as-rhs-error.slang new file mode 100644 index 000000000..9ad71afde --- /dev/null +++ b/tests/language-feature/interface-as-rhs-error.slang @@ -0,0 +1,73 @@ +//TEST:SIMPLE(filecheck=CHECK): -target spirv + +interface IMyInterface +{ + int getValue(); +} + +struct ConcreteImpl : IMyInterface +{ + int getValue() { return 42; } +} + +struct AnotherType +{ + float value; +} + +// No error messages should show for concrete types above +//CHECK-NOT:: error + +// These should produce errors - interface types as RHS +bool testIsOperatorWithInterface() +{ + //CHECK: ([[# @LINE+1]]): error 30301: 'is' and 'as' operators do not support interface types as the right-hand side + return (T is IMyInterface); +} + +void testAsOperatorWithInterface(T value) +{ + //CHECK: ([[# @LINE+1]]): error 30301: 'is' and 'as' operators do not support interface types as the right-hand side + let result = value as IMyInterface; +} + +// No error messages should show for concrete types below +//CHECK-NOT:: error + +// These should work - concrete types as RHS +bool testIsOperatorWithConcreteType() +{ + return (T is ConcreteImpl); // Should compile without error +} + +void testAsOperatorWithConcreteType(T value) +{ + // Test as operator with concrete types - should compile without error + let result = value as ConcreteImpl; +} + +void main() +{ + ConcreteImpl impl; + AnotherType other; + + // Test error cases - these should produce the errors checked above + bool result1 = testIsOperatorWithInterface(); + testAsOperatorWithInterface(impl); + + // Test success cases - these should compile without errors + // If ANY of these had errors, compilation would fail + bool result2 = testIsOperatorWithConcreteType(); + testAsOperatorWithConcreteType(impl); + + // Additional concrete type tests + bool isTest1 = (impl is ConcreteImpl); + bool isTest2 = (other is AnotherType); + bool isTest3 = (ConcreteImpl is ConcreteImpl); + bool isTest4 = (AnotherType is ConcreteImpl); + + // Test as operator directly + let asTest1 = impl as AnotherType; + let asTest2 = other as ConcreteImpl; + let asTest3 = impl as ConcreteImpl; +} -- cgit v1.2.3