diff options
4 files changed, 93 insertions, 1 deletions
diff --git a/source/slang/slang-check-overload.cpp b/source/slang/slang-check-overload.cpp index 21fc21df6..b818c9e06 100644 --- a/source/slang/slang-check-overload.cpp +++ b/source/slang/slang-check-overload.cpp @@ -711,7 +711,35 @@ bool SemanticsVisitor::TryCheckOverloadCandidateTypes( } else { - arg.argExpr = coerce(CoercionSite::Argument, paramType, arg.argExpr); + Expr* coercedExpr = coerce(CoercionSite::Argument, paramType, arg.argExpr); + + // Check if concrete-to-interface coercion caused loss of l-valueness. + if (coercedExpr && !coercedExpr->type.isLeftValue && paramType.isLeftValue && + !isInterfaceType(arg.type) && isInterfaceType(paramType.type)) + { + if (context.mode != OverloadResolveContext::Mode::JustTrying) + { + String name; + if (candidate.flavor == OverloadCandidate::Flavor::Func) + { + auto decl = getParameters( + m_astBuilder, + candidate.item.declRef.as<CallableDecl>())[paramIndex]; + name = getText(decl.getName()); + } + else + name.append(paramIndex, 10); + + getSink()->diagnose( + context.loc, + Diagnostics::concreteArgumentToOutputInterface, + name, + arg.type, + paramType.type); + } + return {nullptr, nullptr}; + } + arg.argExpr = coercedExpr; } return arg; }; diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 089b57c38..6d84792fb 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -761,6 +761,13 @@ DIAGNOSTIC( "cannot specialize generic '$0' with the provided arguments.") DIAGNOSTIC(30076, Error, globalVarCannotHaveOpaqueType, "global variable cannot have opaque type.") +DIAGNOSTIC( + 30077, + Error, + concreteArgumentToOutputInterface, + "argument passed to parameter '$0' is of concrete type '$1', but interface-typed output " + "parameters require interface-typed arguments. To allow passing a concrete type to this " + "function, you can replace '$2 $0' with a generic 'T $0' and a 'where T : $2' constraint.") DIAGNOSTIC(-1, Note, doYouMeanStaticConst, "do you intend to define a `static const` instead?") DIAGNOSTIC(-1, Note, doYouMeanUniform, "do you intend to define a `uniform` parameter instead?") diff --git a/tests/diagnostics/concrete-argument-to-output-interface.slang b/tests/diagnostics/concrete-argument-to-output-interface.slang new file mode 100644 index 000000000..cfe447d94 --- /dev/null +++ b/tests/diagnostics/concrete-argument-to-output-interface.slang @@ -0,0 +1,49 @@ +//DIAGNOSTIC_TEST:SIMPLE: + +interface IThing +{ + [mutating] + void f(); + + void g(); +} + +struct MyThing: IThing +{ + int a = 0; + + [mutating] + void f() + { + a = 10; + } + + void g() {} +} + +void g(IThing x) +{ + x.g(); +} + +void f(inout IThing x) +{ + x.f(); +} + +void h<T:IThing>(inout T x) +{ + x.f(); +} + +void entry() +{ + MyThing concrete; + IThing interfaceTyped = MyThing(); + + g(interfaceTyped); // No error + g(concrete); // No error + f(interfaceTyped); // No error + h(concrete); // No error + f(concrete); // ERROR! +} diff --git a/tests/diagnostics/concrete-argument-to-output-interface.slang.expected b/tests/diagnostics/concrete-argument-to-output-interface.slang.expected new file mode 100644 index 000000000..b979d01a3 --- /dev/null +++ b/tests/diagnostics/concrete-argument-to-output-interface.slang.expected @@ -0,0 +1,8 @@ +result code = -1 +standard error = { +tests/diagnostics/concrete-argument-to-output-interface.slang(48): error 30077: argument passed to parameter 'x' is of concrete type 'MyThing', but interface-typed output parameters require interface-typed arguments. To allow passing a concrete type to this function, you can replace 'IThing x' with a generic 'T x' and a 'where T : IThing' constraint. + f(concrete); // ERROR! + ^ +} +standard output = { +} |
