<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slang.git/tests/language-feature/properties/property-in-interface.slang, branch master</title>
<subtitle>Making it easier to work with shaders</subtitle>
<id>https://git.yummers.dev/slang.git/atom?h=master</id>
<link rel='self' href='https://git.yummers.dev/slang.git/atom?h=master'/>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/'/>
<updated>2025-02-05T18:37:03+00:00</updated>
<entry>
<title>Feature/initialize list side branch (#6058)</title>
<updated>2025-02-05T18:37:03+00:00</updated>
<author>
<name>kaizhangNV</name>
<email>149626564+kaizhangNV@users.noreply.github.com</email>
</author>
<published>2025-02-05T18:37:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=9ec6b91686b651d959fd9ffbec283845bd725dd6'/>
<id>urn:sha1:9ec6b91686b651d959fd9ffbec283845bd725dd6</id>
<content type='text'>
* SP004: implement initialize list translation to ctor

- We synthesize a member-wise constructor for each struct follow
   the rules described in SP004.
- Add logic to translate the initialize list to constructor invoke
- Add cuda-host decoration for the synthesized constructor
- Remove the default constructor when we have a valid member init constructor
- Disable -zero-initialize option, will re-implement it in followup (#6109).
- Fix the overload lookup issue
    When creating invoke expression for ctor, we need to call
    ResolveInvoke() to find us the best candidates, however
    the existing lookup logic could find us the base constructor
    for child struct, we should eliminate this case by providing
    the LookupOptions::IgnoreInheritance to lookup, this requires
    us to create a subcontext on SemanticsVisitor to indicate that
    we only want to use this option on looking the constructor.
- Do not implicit initialize a struct that doesn't have explicit default
   constructor.

Co-authored-by: slangbot &lt;186143334+slangbot@users.noreply.github.com&gt;</content>
</entry>
<entry>
<title>Implement explciit binding for metal and wgsl. (#5778)</title>
<updated>2024-12-06T03:33:55+00:00</updated>
<author>
<name>Yong He</name>
<email>yonghe@outlook.com</email>
</author>
<published>2024-12-06T03:33:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=7dabfa76ccfb396e9d2019e2b6e01259d1661dc5'/>
<id>urn:sha1:7dabfa76ccfb396e9d2019e2b6e01259d1661dc5</id>
<content type='text'>
* Respect explicit bindings in wgsl emit.

* Implement explciit binding generation for metal and wgsl.

* Update toc.

* Fix warnings in tests.

* Fix tests.

---------

Co-authored-by: Ellie Hermaszewska &lt;ellieh@nvidia.com&gt;</content>
</entry>
<entry>
<title>Convert more tests to use shader objects (#1659)</title>
<updated>2021-01-15T20:10:06+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2021-01-15T20:10:06+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=2a5d5b32348c33aac7ca62aa9a4c2bb7cff8e08a'/>
<id>urn:sha1:2a5d5b32348c33aac7ca62aa9a4c2bb7cff8e08a</id>
<content type='text'>
This change converts a large number of our existing tests to use the `ShaderObject` support that was added to the `gfx` layer.

In many cases, tests were just updated to pass `-shaderobj` and the result Just Worked.
In other cases, a `name` attribute had to be added to one or more `TEST_INPUT` lines.

For tests that did not work with shader objects "out of the box," I spent a little bit of time trying to get them work, but fell back to letting those tests run in the older mode.
Future changes to the infrastructure will be needed to get those additional tests working in the new path.

Along with the changes to test files, the following implementation changes were made to get additional tests working:

* Because the shader object mode uses explicit register bindings (from reflection), the hacky logic that was offseting `u` registers for D3D12 based on the number of render targets gets disabled (by another hack).

* The "flat" reflection information coming from Slang was not correctly reporting "binding ranges" for things that consumed only uniform data (which would be everything on CUDA/CPU), so it was refactored to properly include binding ranges for anything where the type of the field/variable implied a binding range should be created (even if the `LayoutResourceKind` was `::Uniform`).

* A few fixes were made to the CUDA implementation of `Renderer`, in order to get additional tests up and running. Most of these changes had to do with texture bindings, which hadn't really been tested previously.

In addition, a few changes were made that were attempts at getting more tests working, but didn't actually help. These could be dropped if requested:

* As a quality-of-life feature (not being used) the `object` style of `TEST_INPUT` line is upgraded to support inferring the type to use from the type of the input being set.

* Any `object` shader input lines get ignored in non-shader-object mode.</content>
</entry>
<entry>
<title>Another fix for overriding property decls (#1509)</title>
<updated>2020-08-21T14:33:43+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2020-08-21T14:33:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=5e64ae752407492f17b346e0429a6fd38238fbb6'/>
<id>urn:sha1:5e64ae752407492f17b346e0429a6fd38238fbb6</id>
<content type='text'>
* Another fix for overriding property decls

The central problem we keep running into with `property` decls in `interface`s comes down to two choices:

1. When a member lookup `obj.someName` or a simple lookup for `someName` produces an overloaded result, we make no attempt to resolve the overloading right away, and instead postpone disambiguation until the point where that expression gets *used*, in case the context where it gets used can help in disambiguation (a notable case being when there is a call expression `obj.someName(...)` or `someName(...)`).

2. When looking up members in a the scope of a type (either for `obj.someName` or `someName` in the context of a method), we include all results from base types in the set of overloads returned, even in cases where the type has a direct member that "overrides" the inherited one.

The combination of these factors means that when a `struct` type implements a `property` to satisfy a requirement of an inherited `interface`, then references to `obj.someProp` end up being ambiguous between the property in the concrete `struct` type and the property it inherits through the `interface`.

There is no quick fix possible for issue (2). It might seem that we could just skip over members inherited through `interface`s when doing lookup in a type, but that solution wouldn't apply to inheritance from another `struct` type, or any future scenario where we support default implementations of methods in interfaces. The simple idea of saying that a derived-type member named `M` hides all inherited members named `M` is possible, but would lead to a bad user interface when a type wants to support both a core "bottleneck" method and a bunch of convenience overloads with the same name.

That leaves us with issue (1), and trying to find a reasonable fix for it. The common case is that any expression `e` eventually gets used in a context where it will be be subject to disambiguation:

* If we form a call expression `e(...)`, then the overload resolution logic will (obviously) work to disambiguate which `e` was meant.

* If `e` is used as an argument to another call (`f(... e ...)` or `... + e`), then `e` will be coerced to the expected parameter type for its argument position, and that coercion will disambiguate it (this is the bit that was fixed in #1501)

* If `e` is used in another context where a type is expected/known, it will also be coerced: `if(e)`, `int v = e`, etc.

The problem case that is left behind is any scenario where `e` is not subject to one of the above resolution cases, which mostly amounts to cases where an expression is never coerced to a single fixed type. There are a few important cases where this occurs today:

* When the expression is used as the left-hand side of an assignement (`e = ...`).

* When an expression is used to initialize a variable with an implicit type (`let v = e`).

* When inferring generic arguments from the value arguments at a call site (`f(e)` where `f` is defined as `f&lt;T&gt;(T v)`)

The key connecting thread in each of these cases is that the front-end needs to determine the type of `e` to make progress.

Our semantic checking logic already has functions that try to draw a distinction between the two cases:

* The `CheckTerm()` operation is supposed to be used when we expect that we will eventually coerce or otherwise diambiguate the term, and also in cases where we don't yet know if a term should name a type or a value

* The `CheckExpr()` operation is supposed to be used when we do not expect that we will apply coercion/disambiguation to a term, and need to have assurances that it has been coerced into a non-overloaded expression with a reasonable type

The simple part of the fix made here is to make `CheckExpr()` actually do part of what it is suppsoed to (attempt to disambiguate overloaded terms), and then audit all the call sites to `CheckExpr()` to make sure they are actually ones that intend to opt into that logic.

The messier part of the fix is dealing with generic argument inference, because we need to extract the type of the disambiguated expression for the purposes of inference, but we don't want to disturb the actual argument list at a call site (because type coercion of the arguments is supposed to handle the disambiguation). This part is done with a bit of special-casing in the overload-resolution context, by adding a method that gets the type or an argument after disambiguation (when possible).

* fixup

Co-authored-by: Yong He &lt;yonghe@outlook.com&gt;</content>
</entry>
<entry>
<title>Attempt to fix lookup for members that "override" (#1501)</title>
<updated>2020-08-17T22:28:05+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2020-08-17T22:28:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=697e7fbbbb5dcb448c03a9887e6ef09e328505ef'/>
<id>urn:sha1:697e7fbbbb5dcb448c03a9887e6ef09e328505ef</id>
<content type='text'>
Our current lookup process always finds *all* members of a type, which can include both an inherited member (e.g., from an `interface`) and one that logically overrides/implements it. If something downstream doesn't filter this result down and favor the derived member, then an ambiguity error will result.

To date, this has mostly been a non-issue because we haven't emphasized inheritance, and the main case we did support (`struct` types implemented `interface` methods) gets disambiguated as part of overload resolution for function calls.

Recent changes to support `property` declarations to `interface`s add the possibility for ambiguity between a "base" and "derived" declaration that can't rely on overload resolution for disambiguation.

The approach in this PR is to add disambiguation logic to the other main place where the results of lookup get used. If a lookup result is being assigned to a variable, passed to a function, or otherwise used in a case where a value of a specific type is needed, it will be "coerced" to the desired type. This change makes it so that the first step in the coercion logic is to try to disambiguate the expression that is being coerced.

In order to ensure that an overloaded expression can be detected and resolved even when just checking if coercion is possible, I needed to update the `canCoerce*()` functions to also take the expression that is being tested for coercibility, and not just its type. There is only one case (that I saw) where coercion checks were being made without an expression value available, and that case didn't actually need/want to handle overloading.

In order to test the fixes here, I added logic to the `property`-in-`interface` test to make sure that the critical cases work as expected (references to a derived member using "dot syntax" and "implicit `this`" syntax).

Alternatives Considered
-----------------------

The first attempt at this fix took a simpler approach: I added the disambiguation logic as a post-process on member lookup. That is, given `obj.foo` I would take the `LookupResult` for `foo` and immediately try to filter it to include only the most-derived members. This approach has the major benefit of catching even more use cases of values (and thus helping to ensure that we don't spend forever chasing down more of these ambiguity errors), but it also has two critical problems:

1. If we only trigger disambiguation when looking up `obj.foo`, then we can't do anything to help when `foo` is looked up as an ordinary identifier, but is actually equivalent to `this.foo`. A full fix would require doing this disambiguation on *every* name lookup, which leads to the second issue:

2. It is important that for a method call like `obj.m(...)` we do *not* disambiguate when looking up `obj.m`, and instead let the overload resolution for the call resolve things. That choice is what makes it possible to call an inherited `m` declaration even when there is a derived `m` with a different signature.

Issue (1) is covered by the test case that was added here, but we should probably have a test case for (2) to make sure we don't break that use case.

Caveats
-------

An important case that we don't solve in this PR is when the result of a lookup is captured in a variable without an explicit type:

    let f = obj.foo;

That case also needs disambiguation, and should be addressed in a later change.

A secondary issue is that our approach to prioritizing declarations during lookup is still quite naive. We really need a way for lookup to attach information about nesting of scopes to results (to be clear that results from inner scopes should be preferred over those from outer scopes), as well as have a robust mechanism for comparing the priority of members based on the inheritance graph of a type. This change doesn't do anything to make the situation better or worse.</content>
</entry>
<entry>
<title>Support property declarations in interfaces (#1494)</title>
<updated>2020-08-14T00:56:20+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2020-08-14T00:56:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=2bfe62afb381f23dcbd39dfd6ba7448050272861'/>
<id>urn:sha1:2bfe62afb381f23dcbd39dfd6ba7448050272861</id>
<content type='text'>
There are two main features in this change. First, we allow for `interface`s to declare `property` requirements, which can be satisfied by matching `property` declarations in a type that conforms to the interface:

    interface IRectangle
    {
        property float width { get; }
        property float height { get; }
    }

    struct Square : IRectangle
    {
        float size;
        property float width { get { return size; } }
        property float height { get { return size; } }
    }

Second, we allow a type to satisfy a `property` requirement with an ordinary field of the same name:

    struct Rectangle : IRectangle
    {
        float width;
        float height;
        // no explicit `property` declarations needed
    }

The implementation of these features is mostly in `slang-check-decl.cpp` in the logic for checking conformance of a type to an interface.

The first feature simply requires adding logic to checking whether a candidate satisfying `property` declaration matches a required `property` declaration. To do so, it must have the same type, and an accessor to satisfy each of the required accessors.

The second feature requires adding logic to synthesize an AST `property` declaration for a type, based on a required `property` declaration and its accessors. This means that, more or less, any type where `this.name` yields a storage location that does what is needed can satisfy a property requirement (there is no specific rule that says the storage needs to be a field, although that is the most likely case).

The way that witnesses are stored for property declarations probably merits some description. During IR lowering, an abstract storage declaration like a subscript or `property` more or less desugars away, so that the actual interface requirements correspond to the accessors within it (the `get`, `set`, etc.). This means that a witness table should have entries/keys corresponding to the accessors and not the property itself. The process of finding/recording witnesses for `property` requirements thus installs entries for the individual accessors (with care taken to only install accessor witnesses once we are sure we have witnesses for all the requirements). Currently, the code also installs an entry for the property itself, although that is not strictly required, and might not be something we continue to do long-term.

(Aside: it was somewhat surprising that an end-to-end test of `property` declarations in `interface`s Just Worked without any changes to IR lowering.)

As we continue to write more code that synthesizes and checks AST expressions/statements, it becomes necessary to refactor the semantic checking logic so that it splits the recursive part (e.g., checking the operands of an assignment) from the validation part (e.g., checking that the assignment itself is valid). It is probably too big of a change to justify at this point, but it might be valuable in the future to have distinct hierarchies that represent unchecked and checked ASTs, with semantic checking mostly being a transformation from one to the other. The benefit of such a change is we could factor out a distinct "builder" API for constructing validated/checked AST nodes, with both semantic checking and AST synthesis being clients of that API.</content>
</entry>
</feed>
