@@ -910,6 +910,75 @@ ${this.ctx.pre}}`;
910910 return snip ( stitch `${ this . ctx . resolve ( schema ) . value } (${ args } )` , schema , 'runtime' ) ;
911911 }
912912
913+ public _return ( statement : tinyest . Return ) : string {
914+ const returnNode = statement [ 1 ] ;
915+
916+ if ( returnNode !== undefined ) {
917+ const expectedReturnType = this . ctx . topFunctionReturnType ;
918+ let returnSnippet = expectedReturnType
919+ ? this . _typedExpression ( returnNode , expectedReturnType )
920+ : this . _expression ( returnNode ) ;
921+
922+ if ( returnSnippet . value instanceof RefOperator ) {
923+ throw new WgslTypeError (
924+ stitch `Cannot return references, returning '${ returnSnippet . value . snippet } '` ,
925+ ) ;
926+ }
927+
928+ // Arguments cannot be returned from functions without copying. A simple example why is:
929+ // const identity = (x) => {
930+ // 'use gpu';
931+ // return x;
932+ // };
933+ //
934+ // const foo = (arg: d.v3f) => {
935+ // 'use gpu';
936+ // const marg = identity(arg);
937+ // marg.x = 1; // 'marg's origin would be 'runtime', so we wouldn't be able to track this misuse.
938+ // };
939+ if (
940+ returnSnippet . origin === 'argument' &&
941+ ! wgsl . isNaturallyEphemeral ( returnSnippet . dataType ) &&
942+ // Only restricting this use in non-entry functions, as the function
943+ // is giving up ownership of all references anyway.
944+ this . ctx . topFunctionScope ?. functionType === 'normal'
945+ ) {
946+ throw new WgslTypeError (
947+ stitch `Cannot return references to arguments, returning '${ returnSnippet } '. Copy the argument before returning it.` ,
948+ ) ;
949+ }
950+
951+ if (
952+ ! expectedReturnType &&
953+ ! isEphemeralSnippet ( returnSnippet ) &&
954+ returnSnippet . origin !== 'this-function'
955+ ) {
956+ const str = this . ctx . resolve ( returnSnippet . value , returnSnippet . dataType ) . value ;
957+ const typeStr = this . ctx . resolve ( unptr ( returnSnippet . dataType ) ) . value ;
958+ throw new WgslTypeError (
959+ `'return ${ str } ;' is invalid, cannot return references.
960+ -----
961+ Try 'return ${ typeStr } (${ str } );' instead.
962+ -----` ,
963+ ) ;
964+ }
965+
966+ returnSnippet = tryConvertSnippet (
967+ this . ctx ,
968+ returnSnippet ,
969+ unptr ( returnSnippet . dataType ) as wgsl . AnyWgslData ,
970+ false ,
971+ ) ;
972+
973+ invariant ( returnSnippet . dataType !== UnknownData , 'Return type should be known' ) ;
974+
975+ this . ctx . reportReturnType ( returnSnippet . dataType ) ;
976+ return stitch `${ this . ctx . pre } return ${ returnSnippet } ;` ;
977+ }
978+
979+ return `${ this . ctx . pre } return;` ;
980+ }
981+
913982 public _statement ( statement : tinyest . Statement ) : string {
914983 if ( typeof statement === 'string' ) {
915984 const id = this . _identifier ( statement ) ;
@@ -923,72 +992,7 @@ ${this.ctx.pre}}`;
923992 }
924993
925994 if ( statement [ 0 ] === NODE . return ) {
926- const returnNode = statement [ 1 ] ;
927-
928- if ( returnNode !== undefined ) {
929- const expectedReturnType = this . ctx . topFunctionReturnType ;
930- let returnSnippet = expectedReturnType
931- ? this . _typedExpression ( returnNode , expectedReturnType )
932- : this . _expression ( returnNode ) ;
933-
934- if ( returnSnippet . value instanceof RefOperator ) {
935- throw new WgslTypeError (
936- stitch `Cannot return references, returning '${ returnSnippet . value . snippet } '` ,
937- ) ;
938- }
939-
940- // Arguments cannot be returned from functions without copying. A simple example why is:
941- // const identity = (x) => {
942- // 'use gpu';
943- // return x;
944- // };
945- //
946- // const foo = (arg: d.v3f) => {
947- // 'use gpu';
948- // const marg = identity(arg);
949- // marg.x = 1; // 'marg's origin would be 'runtime', so we wouldn't be able to track this misuse.
950- // };
951- if (
952- returnSnippet . origin === 'argument' &&
953- ! wgsl . isNaturallyEphemeral ( returnSnippet . dataType ) &&
954- // Only restricting this use in non-entry functions, as the function
955- // is giving up ownership of all references anyway.
956- this . ctx . topFunctionScope ?. functionType === 'normal'
957- ) {
958- throw new WgslTypeError (
959- stitch `Cannot return references to arguments, returning '${ returnSnippet } '. Copy the argument before returning it.` ,
960- ) ;
961- }
962-
963- if (
964- ! expectedReturnType &&
965- ! isEphemeralSnippet ( returnSnippet ) &&
966- returnSnippet . origin !== 'this-function'
967- ) {
968- const str = this . ctx . resolve ( returnSnippet . value , returnSnippet . dataType ) . value ;
969- const typeStr = this . ctx . resolve ( unptr ( returnSnippet . dataType ) ) . value ;
970- throw new WgslTypeError (
971- `'return ${ str } ;' is invalid, cannot return references.
972- -----
973- Try 'return ${ typeStr } (${ str } );' instead.
974- -----` ,
975- ) ;
976- }
977-
978- returnSnippet = tryConvertSnippet (
979- this . ctx ,
980- returnSnippet ,
981- unptr ( returnSnippet . dataType ) as wgsl . AnyWgslData ,
982- false ,
983- ) ;
984-
985- invariant ( returnSnippet . dataType !== UnknownData , 'Return type should be known' ) ;
986-
987- this . ctx . reportReturnType ( returnSnippet . dataType ) ;
988- return stitch `${ this . ctx . pre } return ${ returnSnippet } ;` ;
989- }
990-
991- return `${ this . ctx . pre } return;` ;
995+ return this . _return ( statement ) ;
992996 }
993997
994998 if ( statement [ 0 ] === NODE . if ) {
0 commit comments