summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source/slang/slang-check-overload.cpp30
-rw-r--r--source/slang/slang-diagnostic-defs.h7
-rw-r--r--tests/diagnostics/concrete-argument-to-output-interface.slang49
-rw-r--r--tests/diagnostics/concrete-argument-to-output-interface.slang.expected8
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 = {
+}