]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-sfc): fix script setup ref assignment codegen edge case (#4520)
authoredison <daiwei521@126.com>
Sun, 5 Sep 2021 22:02:50 +0000 (06:02 +0800)
committerGitHub <noreply@github.com>
Sun, 5 Sep 2021 22:02:50 +0000 (18:02 -0400)
fix #4514

packages/compiler-core/src/transforms/transformExpression.ts
packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
packages/compiler-sfc/__tests__/compileScript.spec.ts
packages/compiler-sfc/src/compileScript.ts
packages/runtime-core/src/apiSetupHelpers.ts

index 285c07e2bb714479bd051c2648ebca980da3733c..96284d179bf8f68fc3216360b7a9df13bb80cd59 100644 (file)
@@ -99,7 +99,8 @@ export function processExpression(
   // function params
   asParams = false,
   // v-on handler values may contain multiple statements
-  asRawStatements = false
+  asRawStatements = false,
+  localVars: Record<string, number> = Object.create(context.identifiers)
 ): ExpressionNode {
   if (__BROWSER__) {
     if (__DEV__) {
@@ -127,7 +128,7 @@ export function processExpression(
       const isDestructureAssignment =
         parent && isInDestructureAssignment(parent, parentStack)
 
-      if (type === BindingTypes.SETUP_CONST) {
+      if (type === BindingTypes.SETUP_CONST || localVars[raw]) {
         return raw
       } else if (type === BindingTypes.SETUP_REF) {
         return `${raw}.value`
@@ -149,7 +150,13 @@ export function processExpression(
           const { right: rVal, operator } = parent as AssignmentExpression
           const rExp = rawExp.slice(rVal.start! - 1, rVal.end! - 1)
           const rExpString = stringifyExpression(
-            processExpression(createSimpleExpression(rExp, false), context)
+            processExpression(
+              createSimpleExpression(rExp, false),
+              context,
+              false,
+              false,
+              knownIds
+            )
           )
           return `${context.helperString(IS_REF)}(${raw})${
             context.isTS ? ` //@ts-ignore\n` : ``
@@ -190,6 +197,7 @@ export function processExpression(
         return `$${type}.${raw}`
       }
     }
+
     // fallback to ctx
     return `_ctx.${raw}`
   }
@@ -246,7 +254,6 @@ export function processExpression(
   }
 
   type QualifiedId = Identifier & PrefixMeta
-
   const ids: QualifiedId[] = []
   const parentStack: Node[] = []
   const knownIds: Record<string, number> = Object.create(context.identifiers)
index b3ffe8e2c1a18d958296eae4b0d6f53bd57dff5d..430b2993f618a0e4c5aceea16687325f51ecc4d3 100644 (file)
@@ -157,7 +157,7 @@ return { props, bar }
 }"
 `;
 
-exports[`SFC compile <script setup> defineProps/defineEmits in multi-variable decalration (full removal) 1`] = `
+exports[`SFC compile <script setup> defineProps/defineEmits in multi-variable declaration (full removal) 1`] = `
 "export default {
   props: ['item'],
   emits: ['a'],
@@ -173,7 +173,7 @@ return { props, emit }
 }"
 `;
 
-exports[`SFC compile <script setup> defineProps/defineEmits in multi-variable decalration 1`] = `
+exports[`SFC compile <script setup> defineProps/defineEmits in multi-variable declaration 1`] = `
 "export default {
   props: ['item'],
   emits: ['a'],
@@ -506,7 +506,7 @@ return (_ctx, _push, _parent, _attrs) => {
 `;
 
 exports[`SFC compile <script setup> inlineTemplate mode template assignment expression codegen 1`] = `
-"import { createElementVNode as _createElementVNode, isRef as _isRef, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
+"import { createElementVNode as _createElementVNode, isRef as _isRef, unref as _unref, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
 
 import { ref } from 'vue'
         
@@ -534,6 +534,26 @@ return (_ctx, _cache) => {
     }),
     _createElementVNode(\\"div\\", {
       onClick: _cache[4] || (_cache[4] = $event => (_isRef(v) ? v.value -= 1 : v -= 1))
+    }),
+    _createElementVNode(\\"div\\", {
+      onClick: _cache[5] || (_cache[5] = () => {
+              let a = '' + _unref(lett)           
+              _isRef(v) ? v.value = a : v = a
+           })
+    }),
+    _createElementVNode(\\"div\\", {
+      onClick: _cache[6] || (_cache[6] = () => {
+              // nested scopes
+              (()=>{
+                let x = _ctx.a
+                (()=>{
+                  let z = x
+                  let z2 = z
+                })
+                let lz = _ctx.z
+              })        
+              _isRef(v) ? v.value = _ctx.a : v = _ctx.a
+           })
     })
   ], 64 /* STABLE_FRAGMENT */))
 }
index 6360b63c25212afb687c4a4dafd3dd9d8df95143..a93be902e47a4498acb6cc66b37e81140d442512 100644 (file)
@@ -98,7 +98,7 @@ const myEmit = defineEmits(['foo', 'bar'])
   emits: ['foo', 'bar'],`)
   })
 
-  test('defineProps/defineEmits in multi-variable decalration', () => {
+  test('defineProps/defineEmits in multi-variable declaration', () => {
     const { content } = compile(`
     <script setup>
     const props = defineProps(['item']),
@@ -112,7 +112,7 @@ const myEmit = defineEmits(['foo', 'bar'])
     expect(content).toMatch(`emits: ['a'],`)
   })
 
-  test('defineProps/defineEmits in multi-variable decalration (full removal)', () => {
+  test('defineProps/defineEmits in multi-variable declaration (full removal)', () => {
     const { content } = compile(`
     <script setup>
     const props = defineProps(['item']),
@@ -517,6 +517,22 @@ defineExpose({ foo: 123 })
           <div @click="lett = count"/>
           <div @click="v += 1"/>
           <div @click="v -= 1"/>
+          <div @click="() => {
+              let a = '' + lett           
+              v = a
+           }"/>
+           <div @click="() => {
+              // nested scopes
+              (()=>{
+                let x = a
+                (()=>{
+                  let z = x
+                  let z2 = z
+                })
+                let lz = z
+              })        
+              v = a
+           }"/>
         </template>
         `,
         { inlineTemplate: true }
@@ -531,6 +547,8 @@ defineExpose({ foo: 123 })
       )
       expect(content).toMatch(`_isRef(v) ? v.value += 1 : v += 1`)
       expect(content).toMatch(`_isRef(v) ? v.value -= 1 : v -= 1`)
+      expect(content).toMatch(`_isRef(v) ? v.value = a : v = a`)
+      expect(content).toMatch(`_isRef(v) ? v.value = _ctx.a : v = _ctx.a`)
       assertCode(content)
     })
 
index 13c2a49380372786468a9bd8db1a366713b9441a..b42881b300e1b08acd717a4c0116b8c4f456f6db 100644 (file)
@@ -526,7 +526,7 @@ export function compileScript(
   /**
    * check defaults. If the default object is an object literal with only
    * static properties, we can directly generate more optimzied default
-   * decalrations. Otherwise we will have to fallback to runtime merging.
+   * declarations. Otherwise we will have to fallback to runtime merging.
    */
   function checkStaticDefaults() {
     return (
@@ -895,7 +895,7 @@ export function compileScript(
       }
     }
 
-    // walk decalrations to record declared bindings
+    // walk declarations to record declared bindings
     if (
       (node.type === 'VariableDeclaration' ||
         node.type === 'FunctionDeclaration' ||
index 075d0a9e10e900d455cbce0eeed5898db056e798..54391fc42294d63daff97d92f9e032a24e096351 100644 (file)
@@ -40,7 +40,7 @@ const warnRuntimeUsage = (method: string) =>
  * })
  * ```
  *
- * Equivalent type-based decalration:
+ * Equivalent type-based declaration:
  * ```ts
  * // will be compiled into equivalent runtime declarations
  * const props = defineProps<{
@@ -79,7 +79,7 @@ export function defineProps() {
  * const emit = defineEmits(['change', 'update'])
  * ```
  *
- * Example type-based decalration:
+ * Example type-based declaration:
  * ```ts
  * const emit = defineEmits<{
  *   (event: 'change'): void
@@ -147,7 +147,7 @@ type PropsWithDefaults<Base, Defaults> = Base &
 
 /**
  * Vue `<script setup>` compiler macro for providing props default values when
- * using type-based `defineProps` decalration.
+ * using type-based `defineProps` declaration.
  *
  * Example usage:
  * ```ts