@@ -717,6 +717,26 @@ ${this.ctx.pre}}`;
717717 ) ;
718718 }
719719
720+ // Arguments cannot be returned from functions without copying. A simple example why is:
721+ // const identity = (x) => {
722+ // 'use gpu';
723+ // return x;
724+ // };
725+ //
726+ // const foo = (arg: d.v3f) => {
727+ // 'use gpu';
728+ // const marg = identity(arg);
729+ // marg.x = 1; // 'marg's origin would be 'runtime', so we wouldn't be able to track this misuse.
730+ // };
731+ if (
732+ returnSnippet . origin === 'argument' &&
733+ ! isEphemeralSnippet ( returnSnippet )
734+ ) {
735+ throw new WgslTypeError (
736+ stitch `Cannot return references to arguments, returning '${ returnSnippet } '. Copy the argument before returning it.` ,
737+ ) ;
738+ }
739+
720740 if (
721741 ! expectedReturnType &&
722742 ! isEphemeralSnippet ( returnSnippet ) &&
@@ -794,6 +814,10 @@ ${this.ctx.pre}else ${alternate}`;
794814 ) ;
795815 }
796816
817+ const ephemeral = isEphemeralSnippet ( eq ) ;
818+ let dataType = eq . dataType as wgsl . AnyWgslData ;
819+ const naturallyEphemeral = wgsl . isNaturallyEphemeral ( dataType ) ;
820+
797821 if ( isLooseData ( eq . dataType ) ) {
798822 throw new Error (
799823 `Cannot create variable '${ rawId } ' with loose data type.` ,
@@ -821,14 +845,9 @@ ${this.ctx.pre}else ${alternate}`;
821845 } ;`;
822846 }
823847
824- let dataType = eq . dataType as wgsl . AnyWgslData ;
825-
826848 // Assigning a reference to a `const` variable means we store the pointer
827849 // of the rhs.
828- if (
829- ! isEphemeralSnippet ( eq ) ||
830- ( eq . origin === 'argument' && ! wgsl . isNaturallyEphemeral ( dataType ) )
831- ) {
850+ if ( ! ephemeral ) {
832851 // Referential
833852 if ( stmtType === NODE . let ) {
834853 const rhsStr = this . ctx . resolve ( eq . value ) . value ;
@@ -866,11 +885,32 @@ ${this.ctx.pre}else ${alternate}`;
866885 }
867886 } else {
868887 // Non-referential
869- if (
870- stmtType === NODE . const &&
871- wgsl . isNaturallyEphemeral ( dataType )
872- ) {
873- varType = eq . origin === 'constant' ? 'const' : 'let' ;
888+
889+ if ( eq . origin === 'argument' ) {
890+ if ( stmtType === NODE . let ) {
891+ const rhsStr = this . ctx . resolve ( eq . value ) . value ;
892+ const rhsTypeStr =
893+ this . ctx . resolve ( toStorable ( eq . dataType as wgsl . StorableData ) )
894+ . value ;
895+
896+ throw new WgslTypeError (
897+ `'let ${ rawId } = ${ rhsStr } ' is invalid, because references to arguments cannot be assigned to 'let' variable declarations.
898+ -----
899+ - Try 'let ${ rawId } = ${ rhsTypeStr } (${ rhsStr } )' if you need to reassign '${ rawId } ' later
900+ - Try 'const ${ rawId } = ${ rhsStr } ' if you won't reassign '${ rawId } ' later.
901+ -----` ,
902+ ) ;
903+ }
904+ varType = 'let' ;
905+ }
906+
907+ if ( stmtType === NODE . const ) {
908+ if ( eq . origin === 'argument' ) {
909+ // Arguments cannot be mutated, so we 'let' them be (kill me)
910+ varType = 'let' ;
911+ } else if ( naturallyEphemeral ) {
912+ varType = eq . origin === 'constant' ? 'const' : 'let' ;
913+ }
874914 }
875915 }
876916
0 commit comments