@@ -1024,6 +1024,23 @@ export class Scope {
10241024 evaluate ( expression , values = new Set ( ) , seen_bindings = [ ] , from_fn_call = false ) {
10251025 return new Evaluation ( this , expression , values , seen_bindings , from_fn_call ) ;
10261026 }
1027+
1028+ /**
1029+ * @param {Scope } child
1030+ */
1031+ contains ( child ) {
1032+ let contains = false ;
1033+ /** @type {Scope | null } */
1034+ let curr = child ;
1035+ while ( curr ?. parent != null ) {
1036+ curr = curr ?. parent ;
1037+ if ( curr === this ) {
1038+ contains = true ;
1039+ break ;
1040+ }
1041+ }
1042+ return contains ;
1043+ }
10271044}
10281045
10291046/** @type {Record<BinaryOperator, (left: any, right: any) => any> } */
@@ -1646,7 +1663,12 @@ function get_type_of_ts_node(node, scope) {
16461663 * @returns {any[] }
16471664 */
16481665 function intersect_types ( types ) {
1649- if ( types . includes ( UNKNOWN ) ) return [ UNKNOWN ] ;
1666+ if (
1667+ types . includes ( UNKNOWN ) ||
1668+ types . filter ( ( type ) => ! [ 'symbol' , 'string' , 'number' , 'bigint' ] . includes ( typeof type ) )
1669+ . length > 1
1670+ )
1671+ return [ UNKNOWN ] ;
16501672 /** @type {any[] } */
16511673 let res = [ ] ;
16521674 if (
@@ -1666,14 +1688,9 @@ function get_type_of_ts_node(node, scope) {
16661688 } else {
16671689 res . push ( ...types . filter ( ( type ) => typeof type === 'string' ) ) ;
16681690 }
1669- if (
1670- types . filter ( ( type ) => ! [ 'symbol' , 'string' , 'number' , 'bigint' ] . includes ( typeof type ) )
1671- . length > 1
1672- ) {
1673- res . push ( UNKNOWN ) ;
1674- } else {
1691+ if ( types . some ( ( type ) => ! [ 'symbol' , 'string' , 'number' , 'bigint' ] . includes ( typeof type ) ) ) {
16751692 types . push (
1676- ... types . filter ( ( type ) => ! [ 'symbol' , 'string' , 'number' , 'bigint' ] . includes ( typeof type ) )
1693+ types . find ( ( type ) => ! [ 'symbol' , 'string' , 'number' , 'bigint' ] . includes ( typeof type ) )
16771694 ) ;
16781695 }
16791696 return res ;
@@ -1751,6 +1768,19 @@ const known_globals = [
17511768
17521769let fn_cache = new Map ( ) ;
17531770
1771+ /**
1772+ * @param {Expression } callee
1773+ * @param {Scope } scope
1774+ */
1775+ function is_global_class ( callee , scope ) {
1776+ let keypath = get_global_keypath ( callee , scope ) ;
1777+ if ( keypath === null ) return false ;
1778+ if ( keypath . match ( / ^ ( g l o b a l T h i s \. ) + / ) ) {
1779+ keypath = keypath . replace ( / ^ ( g l o b a l T h i s \. ) + / , '' ) ;
1780+ }
1781+ return global_classes . includes ( keypath ) ;
1782+ }
1783+
17541784/**
17551785 * Analyzes and partially evaluates the provided function.
17561786 * @param {FunctionExpression | ArrowFunctionExpression | FunctionDeclaration } fn
@@ -1806,21 +1836,31 @@ function evaluate_function(fn, binding, stack = new Set(), [...seen_bindings] =
18061836 } ;
18071837 const uses_implicit_return =
18081838 fn . type === 'ArrowFunctionExpression' && fn . body . type !== 'BlockStatement' ;
1839+ function needs_check ( purity = true , throwability = true ) {
1840+ if ( ! throwability ) {
1841+ return analysis . pure ;
1842+ }
1843+ if ( ! purity ) {
1844+ return analysis . never_throws ;
1845+ }
1846+ return analysis . pure || analysis . never_throws ;
1847+ }
18091848 /**
18101849 * @param {CallExpression | NewExpression } node
18111850 * @param {import('zimmerframe').Context<AST.SvelteNode, typeof state> } context
18121851 */
18131852 function handle_call_expression ( node , context ) {
18141853 const { callee : call , arguments : args } = node ;
1815- const callee = context . visit ( call , {
1816- ...context . state ,
1817- current_call : ( node . type === 'CallExpression' ? CALL_EXPRESSION : NEW_EXPRESSION ) | 0
1818- } ) ;
1854+ const callee = /** @type {Expression } */ (
1855+ context . visit ( call , {
1856+ ...context . state ,
1857+ current_call : ( node . type === 'CallExpression' ? CALL_EXPRESSION : NEW_EXPRESSION ) | 0
1858+ } )
1859+ ) ;
18191860 for ( let arg of args ) {
18201861 context . visit ( arg ) ;
18211862 }
1822- if ( analysis . pure || analysis . never_throws ) {
1823- // don't check unless we think the function is pure or error-free
1863+ if ( needs_check ( ) ) {
18241864 if ( callee . type === 'Identifier' ) {
18251865 const binding = context . state . scope . get ( callee . name ) ;
18261866 if (
@@ -1851,21 +1891,24 @@ function evaluate_function(fn, binding, stack = new Set(), [...seen_bindings] =
18511891 ) ;
18521892 analysis . pure &&= child_analysis . pure ;
18531893 analysis . never_throws &&= child_analysis . never_throws ;
1894+ } else if ( node . type === 'NewExpression' && ! is_global_class ( callee , context . state . scope ) ) {
1895+ analysis . pure = false ;
1896+ analysis . never_throws = false ;
18541897 }
18551898 }
18561899 }
18571900 walk ( /** @type {AST.SvelteNode } */ ( fn ) , state , {
18581901 MemberExpression ( node , context ) {
18591902 const keypath = get_global_keypath ( node , context . state . scope ) ;
18601903 const evaluated = context . state . scope . evaluate ( node , new Set ( ) , seen_bindings , true ) ;
1861- if ( keypath === null && ! evaluated . is_known ) {
1904+ if ( ! ( keypath !== null && Object . hasOwn ( globals , keypath ) ) && ! evaluated . is_known ) {
18621905 analysis . pure = false ;
18631906 analysis . never_throws = false ;
18641907 }
18651908 context . next ( ) ;
18661909 } ,
18671910 Identifier ( node , context ) {
1868- if ( is_reference ( node , /** @type {Node } */ ( context . path . at ( - 1 ) ) ) ) {
1911+ if ( is_reference ( node , /** @type {Node } */ ( context . path . at ( - 1 ) ) ) && needs_check ( ) ) {
18691912 const binding = context . state . scope . get ( node . name ) ;
18701913 if ( binding !== fn_binding ) {
18711914 if ( binding === null ) {
@@ -1878,21 +1921,10 @@ function evaluate_function(fn, binding, stack = new Set(), [...seen_bindings] =
18781921 binding . scope !== fn_scope &&
18791922 binding . updated &&
18801923 context . state . current_call === 0 &&
1881- ! seen_bindings . includes ( binding )
1924+ ! seen_bindings . includes ( binding ) &&
1925+ needs_check ( true , false )
18821926 ) {
1883- let has_fn_scope = false ;
1884- /** @type {null | Scope } */
1885- let curr = binding . scope ;
1886- while ( curr !== null ) {
1887- curr = curr ?. parent ?? null ;
1888- if ( fn_scope === curr ) {
1889- has_fn_scope = true ;
1890- break ;
1891- }
1892- }
1893- if ( ! has_fn_scope ) {
1894- analysis . pure = false ;
1895- }
1927+ analysis . pure &&= fn_scope . contains ( binding . scope ) ;
18961928 seen_bindings . push ( binding ) ;
18971929 }
18981930 if ( binding . kind === 'derived' ) {
@@ -1904,6 +1936,9 @@ function evaluate_function(fn, binding, stack = new Set(), [...seen_bindings] =
19041936 } ,
19051937 CallExpression : handle_call_expression ,
19061938 NewExpression : handle_call_expression ,
1939+ TaggedTemplateExpression ( node , context ) {
1940+ return handle_call_expression ( b . call ( node . tag , node . quasi ) , context ) ;
1941+ } ,
19071942 ThrowStatement ( node , context ) {
19081943 if (
19091944 fn . type !== 'FunctionDeclaration' ||
0 commit comments