summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2018-09-13 14:32:13 -0700
committerGitHub <noreply@github.com>2018-09-13 14:32:13 -0700
commite1c934972509f4bbd2c05affe565f91e7a1e6c16 (patch)
tree7ba91ee54fb1eaeda5e16cc3cf7260a3830fbcf4
parent929745d75f0607ab5b2218083ca4ccb493eb6032 (diff)
Add a better error message for common global generic failure (#634)
A common mistake that seems to come up when using global generic type parameters: ```hlsl interface IHero { ... } type_param H : IHero; ParameterBlock<H> gHero; ``` is to accidentally try to specialize the type parameter `H` using `H` itself as the argument (instead of some concrete type like `Batman`). The current front-end checks naively let this pass, because `H` satisfies all the requirements (it sure does declare that it implements `IHero`, which is the only requirement we have). This currently leads to downstream failure when we generate code with generic type parameters still left in the IR. This change implements a simple fix which is to: - Check when we are trying to specialize a global generic parameter using another global generic parameter, since this is currently always a mistake - Add a special-case diagnostic for the 99% case of this failure, which is specializing a type parameter to itself This fix is primarily motivated by the way generics support will initially be implemented in Falcor.
-rw-r--r--source/slang/check.cpp36
-rw-r--r--source/slang/diagnostic-defs.h5
2 files changed, 41 insertions, 0 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index 42bcfe4b5..7f91ac0c3 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -8635,6 +8635,42 @@ namespace Slang
SLANG_ASSERT(argIndex < globalGenericArgs.Count());
auto globalGenericArg = globalGenericArgs[argIndex];
+ // As a quick sanity check, see if the argument that is being supplied for a parameter
+ // is just the parameter itself, because this should always be an error:
+ //
+ if( auto argDeclRefType = globalGenericArg->As<DeclRefType>() )
+ {
+ auto argDeclRef = argDeclRefType->declRef;
+ if(auto argGenericParamDeclRef = argDeclRef.As<GlobalGenericParamDecl>())
+ {
+ if(argGenericParamDeclRef.getDecl() == globalGenericParam)
+ {
+ // We are trying to specialize a generic parameter using itself.
+ sink->diagnose(globalGenericParam,
+ Diagnostics::cannotSpecializeGlobalGenericToItself,
+ globalGenericParam->getName());
+ sink->diagnose(entryPointFuncDecl,
+ Diagnostics::noteWhenCompilingEntryPoint,
+ entryPointFuncDecl->getName());
+ continue;
+ }
+ else
+ {
+ // We are trying to specialize a generic parameter using a *different*
+ // global generic type parameter.
+ sink->diagnose(globalGenericParam,
+ Diagnostics::cannotSpecializeGlobalGenericToAnotherGenericParam,
+ globalGenericParam->getName(),
+ argGenericParamDeclRef.GetName());
+ sink->diagnose(entryPointFuncDecl,
+ Diagnostics::noteWhenCompilingEntryPoint,
+ entryPointFuncDecl->getName());
+ continue;
+ }
+ }
+ }
+
+
// Create a substitution for this parameter/argument.
RefPtr<GlobalGenericParamSubstitution> subst = new GlobalGenericParamSubstitution();
subst->paramDecl = globalGenericParam;
diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h
index c0c74c78e..83e82fc81 100644
--- a/source/slang/diagnostic-defs.h
+++ b/source/slang/diagnostic-defs.h
@@ -307,9 +307,14 @@ DIAGNOSTIC(38102, Error, accessorMustBeInsideSubscriptOrProperty, "an accessor d
DIAGNOSTIC(38020, Error, mismatchEntryPointTypeArgument, "expecting $0 entry-point type arguments, provided $1.")
DIAGNOSTIC(38021, Error, typeArgumentDoesNotConformToInterface, "type argument `$1` for generic parameter `$0` does not conform to interface `$1`.")
+DIAGNOSTIC(38022, Error, cannotSpecializeGlobalGenericToItself, "the global type parameter '$0' cannot be specialized to itself")
+DIAGNOSTIC(38023, Error, cannotSpecializeGlobalGenericToAnotherGenericParam, "the global type parameter '$0' cannot be specialized using another global type parameter ('$1')")
+DIAGNOSTIC(-1, Note, noteWhenCompilingEntryPoint, "when compiling entry point '$0'")
+
DIAGNOSTIC(38200, Error, recursiveModuleImport, "module `$0` recursively imports itself")
DIAGNOSTIC(39999, Fatal, errorInImportedModule, "error in imported module, compilation ceased.")
+
// 39xxx - Type layout and parameter binding.
DIAGNOSTIC(39000, Error, conflictingExplicitBindingsForParameter, "conflicting explicit bindings for parameter '$0'")