<feed xmlns='http://www.w3.org/2005/Atom'>
<title>slang.git/source/slang/ir-existential.cpp, 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>2019-01-28T22:20:44+00:00</updated>
<entry>
<title>Support function parameters of existential (interface) type (#802)</title>
<updated>2019-01-28T22:20:44+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2019-01-28T22:20:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=3c3513ab501277333d1062ad2737ac4a60dac6f7'/>
<id>urn:sha1:3c3513ab501277333d1062ad2737ac4a60dac6f7</id>
<content type='text'>
* Support function parameters of existential (interface) type

The basic idea here is that you can define a function that takes an interface-type parameter:

```hlsl
interface IThing { void doSOmething(); }
void coolFunction(IThing thing) { ... thing.doSomething() ... }
```

and call it with a concrete value that implements the given interface:

```hlsl
struct Stuff : IThing { void doSomething() { /* secret sauce */ } }
...
Stuff stuff;
coolFunction(stuff);
```

The compiler implementation will specialize `coolFunction` based on the concrete type that was actually passed in, resulting in output code along the lines of:

```hlsl
struct Stuff { ... }
void Stuff_doSomething(Stuff this) { /* secret sauce */ }

void coolFunction_Stuff(Stuff thing) { ... Stuff_doSomething(thing); }
```

In terms of implementation the new specialization approach has been integrated into the existing pass for generic specialization (which has been refactored significantly along the way), because generic specialization can open up opportunities for existential/interface simplification and vice versa, so there is no fixed interleaving of the two passes that can clean up everything.

The new logic therefore subsumes the old code for simplifying existential types (which only worked on local variables) in `ir-existential.{h,cpp}`. The local simplification rules from that implementation have become part of the core specialization pass instead, so that they can open up further transformation opportunities enabled by existential-type simplifications.

This code in place right now only handles the basic case of a function parameter that directly uses an interface type, and not one that wraps up an interface type in an array, structure, etc. Additional simplifications need to be introduced to deal with those cases as well.

* fixup: typos
</content>
</entry>
<entry>
<title>First step toward supporting use of interfaces as existential types (#716)</title>
<updated>2018-12-18T03:26:32+00:00</updated>
<author>
<name>Tim Foley</name>
<email>tfoleyNV@users.noreply.github.com</email>
</author>
<published>2018-12-18T03:26:32+00:00</published>
<link rel='alternate' type='text/html' href='https://git.yummers.dev/slang.git/commit/?id=583c72af28d2dde5c564d5b56d3c5eb4ae4844f6'/>
<id>urn:sha1:583c72af28d2dde5c564d5b56d3c5eb4ae4844f6</id>
<content type='text'>
* First step toward supporting use of interfaces as existential types

Traditional generics involve universal quantification. E.g., a declaration like:

```
void drive&lt;T : IVehicle&gt;(T vehicle);
```

indicates for *for all* types `T` that implement the `IVehicle` interface, the `drive()` function is available.

In contrast, whend directly using an interface type like:

```
IVehicle v = ...;
v.doSomething();
```

we only know that there *exists* some concrete type (we could call it `E`) such that `v` refers to a value of type `E`, and `E` implements the `IVehicle` interface. In order to perform an operation like `v.doSomething()` we need to "open" the existential value so that we can look at the concrete type and how it implements the `IVehicle.doSomething` requirement.

This change adds a very explicit representation of existentials to Slang's IR. An operation like `e = makeExistential(v, w)` creates a value of some existential type (interfaces being our only existential types for now), by wrapping a concrete value `v` (the type of `v` can be seen as an implicit operand) and a witness table `w` showing that the type of `v` implements the requirements of the chosen interface type.

In turn, opening of an existential is handled with operations `extractExistential{Value|Type|WitnessTable}` which pull the corresponding piece of information out of a value of existential type (which somewhere in the code had to have been created with `makeExistential`).

The change includes a trivial simplification pass that can detect cases where an `extractExistential*` operation is applied direclty to a `makeExistential` operation, so that there is only one possible result that could be extracted. This allows for simplification of existential types used in trivial ways for local variables (this is mostly so I can check in a functional test, rather than to actually support useful code involving interfaces right now).

The logic in the semantic checking phase of the compiler is comparatively more complex.
When we are about to perform member lookup given an expression like `obj.member` we will first check if `obj` has an existential type, and if it does we will construct a suitable local context in which we extract the value, type, and witness table from the existential (these all become explicit AST expression nodes), and then use the extracted value as the base of the lookup operation.

The nature of existential values is that two different values with the same existential (interface) type could wrap concrete values with differnt types, so that we need to carefully refer only to the extracted type/value/witness-table of specific *values*. We handle this right now by conceptually moving the existential-type value into a local variable (by introducing a `LetExpr` that amounts to `let v = &lt;init&gt; in &lt;body&gt;`) and then require that the extract expressions must refer to the (immutable) variable declaration from which they are extracting a value.

(Eventually we should expand this so that when using an immutable local variable of existential type we just use that variable as-is rather than introduce a new temporary)

A simple test case is included that uses an interface type in an almost trivial way for a local variable; this test can be run and produces the expected results.
A more complex test case that passes an existential into a function is included, but left disabled because a more aggressive simplification approach is required to generate working code from it.

* Add missing file for expected test output

* Fixups for merge from top-of-tree
</content>
</entry>
</feed>
