diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-11-07 09:38:32 -0800 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-11-07 10:44:07 -0800 |
| commit | 93a444fe1b5f1e3c6da67db4d948df53a0bdb3f6 (patch) | |
| tree | 86e77146bb56f2b486b9705805b80d4520147433 /source/slang | |
| parent | 9640df03814593d2f4b34c36bbec6756b1ed7fba (diff) | |
Attach correct types to subscript accessors
Subscript declarations can have nested "accessor" declarations for the get/set behavior:
```
__subscript(int index) -> float
{
get { ... }
set { ... }
}
```
The AST type checks an expression like `a[i]` into a call to an appropriate `__subscript` declaration, and reads the return type off of that, but doesn't drill down to the individual getters/setters.
During IR code generation, we need to resolve a call to the subscript operation down to the actual getter or setter, since those are what will have the executable code (or be intrinsics). If we have a non-intrinsic accessor, then we end up asking for its "return type" and get NULL, which crashes the compiler.
The fix in this case is to add a bit more semantic checking for accessors, mostly just so that we can have them copy the return type from their parent declaration. While we are at it, this change goes ahead and has an accessor validate that the parent declaration is one that should be allowed, and emit a diagnostic if it is nested in an improper place.
Diffstat (limited to 'source/slang')
| -rw-r--r-- | source/slang/check.cpp | 22 | ||||
| -rw-r--r-- | source/slang/diagnostic-defs.h | 1 |
2 files changed, 23 insertions, 0 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index ed2ed4a1b..6bb7c232f 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -3471,11 +3471,33 @@ namespace Slang decl->SetCheckState(DeclCheckState::CheckedHeader); + for(auto mm : decl->Members) + { + checkDecl(mm); + } + decl->SetCheckState(DeclCheckState::Checked); } void visitAccessorDecl(AccessorDecl* decl) { + // An acessor must appear nested inside a subscript declaration (today), + // or a property declaration (when we add them). It will derive + // its return type from the outer declaration, so we handle both + // of these checks at the same place. + auto parent = decl->ParentDecl; + if(auto parentSubscript = dynamic_cast<SubscriptDecl*>(parent)) + { + decl->ReturnType = parentSubscript->ReturnType; + } + // TODO: when we add "property" declarations, check for them here + else + { + getSink()->diagnose(decl, Diagnostics::accessorMustBeInsideSubscriptOrProperty); + } + + decl->SetCheckState(DeclCheckState::CheckedHeader); + // TODO: check the body! decl->SetCheckState(DeclCheckState::Checked); diff --git a/source/slang/diagnostic-defs.h b/source/slang/diagnostic-defs.h index 52f5d48a0..10b2dbd1e 100644 --- a/source/slang/diagnostic-defs.h +++ b/source/slang/diagnostic-defs.h @@ -246,6 +246,7 @@ DIAGNOSTIC(38003, Error, entryPointSymbolNotAFunction, "entry point '$0' must be DIAGNOSTIC(38100, Error, typeDoesntImplementInterfaceRequirement, "type '$0' does not provide required interface member '$1'") DIAGNOSTIC(38101, Error, thisExpressionOutsideOfTypeDecl, "'this' expression can only be used in members of an aggregate type") DIAGNOSTIC(38102, Error, initializerNotInsideType, "an 'init' declaration is only allowed inside a type or 'extension' declaration") +DIAGNOSTIC(38102, Error, accessorMustBeInsideSubscriptOrProperty, "an accessor declaration is only allowed inside a subscript or property declaration") // // 4xxxx - IL code generation. |
