@@ -14,6 +14,7 @@ import langspec from '../static/langspec.json';
1414import { VERSION } from '../version' ;
1515import { optimizeTeal } from './optimize' ;
1616import { type ARC56Contract , type StructField } from '../types/arc56.d' ;
17+ import { checkRefs } from './ref_checker' ;
1718
1819const MULTI_OUTPUT_TYPES = [ 'split uint128' , 'divmodw output' , 'vrf return values' , 'ecdsa pubkey' ] ;
1920
@@ -116,6 +117,42 @@ type Event = {
116117 argTupleType : TypeInfo ;
117118} ;
118119
120+ /**
121+ *
122+ * @param node The top level node to process
123+ * @param chain The existing expression chain to add to
124+ * @returns The base expression and reversed expression chain `this.txn.sender` ->
125+ * `{ chain: [this.txn, this.txn.sender], base: [this] }`
126+ */
127+ export function getExpressionChain (
128+ node : ExpressionChainNode ,
129+ chain : ExpressionChainNode [ ] = [ ]
130+ ) : { chain : ExpressionChainNode [ ] ; base : ts . Node } {
131+ chain . push ( node ) ;
132+
133+ /**
134+ * The expression on the given node
135+ * `this.txn.sender` -> `this.txn`
136+ */
137+ let expr : ts . Expression = node . getExpression ( ) ;
138+
139+ /* this.txn.applicationArgs! -> this.txn.applicationArgs */
140+ if ( expr . isKind ( ts . SyntaxKind . NonNullExpression ) ) {
141+ expr = expr . getExpression ( ) ;
142+ }
143+
144+ if (
145+ expr . isKind ( ts . SyntaxKind . ElementAccessExpression ) ||
146+ expr . isKind ( ts . SyntaxKind . PropertyAccessExpression ) ||
147+ expr . isKind ( ts . SyntaxKind . CallExpression )
148+ ) {
149+ return getExpressionChain ( expr , chain ) ;
150+ }
151+
152+ chain . reverse ( ) ;
153+ return { base : expr , chain } ;
154+ }
155+
119156async function getSourceMap ( vlqMappings : string ) {
120157 const pcList = vlqMappings . split ( ';' ) . map ( ( m : string ) => {
121158 const decoded = vlq . decode ( m ) ;
@@ -1088,23 +1125,6 @@ export default class Compiler {
10881125 */
10891126 private topLevelNode ! : ts . Node ;
10901127
1091- private mutableRefCheck ( e : ts . Node ) {
1092- const typeInfo = this . getTypeInfo ( e . getType ( ) ) ;
1093- if ( typeInfo . kind !== 'base' ) {
1094- if (
1095- ! (
1096- e . isKind ( ts . SyntaxKind . CallExpression ) ||
1097- e . isKind ( ts . SyntaxKind . ArrayLiteralExpression ) ||
1098- e . isKind ( ts . SyntaxKind . ObjectLiteralExpression )
1099- )
1100- ) {
1101- throw Error (
1102- `Cannot have multiple multiple references to the same object. Use clone to create a deep copy: clone(${ e . getText ( ) } )`
1103- ) ;
1104- }
1105- }
1106- }
1107-
11081128 private getTypeInfo ( type : ts . Type < ts . ts . Type > ) : TypeInfo {
11091129 if ( type . getText ( ) === 'SplitUint128' ) return { kind : 'base' , type : 'split uint128' } ;
11101130 if ( type . getText ( ) === 'DivmodwOutput' ) return { kind : 'base' , type : 'divmodw output' } ;
@@ -2056,8 +2076,6 @@ export default class Compiler {
20562076 if ( ! this . isDynamicArrayOfStaticType ( this . lastType ) )
20572077 throw new Error ( 'Cannot push to dynamic array of dynamic types' ) ;
20582078
2059- this . mutableRefCheck ( node . getArguments ( ) [ 0 ] ) ;
2060-
20612079 this . processNode ( node . getArguments ( ) [ 0 ] ) ;
20622080 this . checkEncoding ( node . getArguments ( ) [ 0 ] , this . lastType ) ;
20632081 this . pushVoid ( node , 'concat' ) ;
@@ -2857,6 +2875,10 @@ export default class Compiler {
28572875
28582876 // Go over all the files we are importing and check for number keywords
28592877 [ sourceFile , ...importedFiles ] . forEach ( ( f ) => {
2878+ if ( f === undefined ) return ;
2879+
2880+ checkRefs ( f , path . relative ( this . cwd , f . getFilePath ( ) ) ) ;
2881+
28602882 f ?. getStatements ( ) . forEach ( ( s ) => {
28612883 const numberKeywords = s . getDescendantsOfKind ( ts . SyntaxKind . NumberKeyword ) ;
28622884
@@ -3655,10 +3677,6 @@ export default class Compiler {
36553677 const { typeHint } = this ;
36563678 if ( typeHint === undefined ) throw Error ( 'Type hint must be provided to process object or array' ) ;
36573679
3658- elements . forEach ( ( e ) => {
3659- this . mutableRefCheck ( e ) ;
3660- } ) ;
3661-
36623680 if (
36633681 typeHint . kind === 'tuple' ||
36643682 typeHint . kind === 'object' ||
@@ -3720,42 +3738,6 @@ export default class Compiler {
37203738 this . processArrayElements ( node . getElements ( ) , node ) ;
37213739 }
37223740
3723- /**
3724- *
3725- * @param node The top level node to process
3726- * @param chain The existing expression chain to add to
3727- * @returns The base expression and reversed expression chain `this.txn.sender` ->
3728- * `{ chain: [this.txn, this.txn.sender], base: [this] }`
3729- */
3730- private getExpressionChain (
3731- node : ExpressionChainNode ,
3732- chain : ExpressionChainNode [ ] = [ ]
3733- ) : { chain : ExpressionChainNode [ ] ; base : ts . Node } {
3734- chain . push ( node ) ;
3735-
3736- /**
3737- * The expression on the given node
3738- * `this.txn.sender` -> `this.txn`
3739- */
3740- let expr : ts . Expression = node . getExpression ( ) ;
3741-
3742- /* this.txn.applicationArgs! -> this.txn.applicationArgs */
3743- if ( expr . isKind ( ts . SyntaxKind . NonNullExpression ) ) {
3744- expr = expr . getExpression ( ) ;
3745- }
3746-
3747- if (
3748- expr . isKind ( ts . SyntaxKind . ElementAccessExpression ) ||
3749- expr . isKind ( ts . SyntaxKind . PropertyAccessExpression ) ||
3750- expr . isKind ( ts . SyntaxKind . CallExpression )
3751- ) {
3752- return this . getExpressionChain ( expr , chain ) ;
3753- }
3754-
3755- chain . reverse ( ) ;
3756- return { base : expr , chain } ;
3757- }
3758-
37593741 private getAccessChain ( node : ts . ElementAccessExpression , chain : ts . ElementAccessExpression [ ] = [ ] ) {
37603742 chain . push ( node ) ;
37613743
@@ -4250,8 +4232,6 @@ export default class Compiler {
42504232 ! this . isDynamicType ( this . storageProps [ getStorageName ( storageExpression ) ! ] . valueType ) ;
42514233
42524234 if ( newValue ) {
4253- this . mutableRefCheck ( newValue ) ;
4254-
42554235 if ( newValue . getType ( ) . isNumberLiteral ( ) ) {
42564236 this . processNewValue ( newValue , elem . type ) ;
42574237 } else {
@@ -4362,8 +4342,6 @@ export default class Compiler {
43624342 }
43634343
43644344 if ( newValue ) {
4365- this . mutableRefCheck ( newValue ) ;
4366-
43674345 if ( this . isDynamicType ( element . type ) ) {
43684346 if ( element . parent ?. arrayType !== 'tuple' ) {
43694347 throw new Error (
@@ -6344,7 +6322,7 @@ export default class Compiler {
63446322 }
63456323 }
63466324
6347- const { base, chain } = this . getExpressionChain ( node ) ;
6325+ const { base, chain } = getExpressionChain ( node ) ;
63486326
63496327 if ( base . isKind ( ts . SyntaxKind . ParenthesizedExpression ) ) {
63506328 if ( ! base . getExpression ( ) . isKind ( ts . SyntaxKind . BinaryExpression ) )
0 commit comments