Repository: sveltejs/svelte (JavaScript)
Date: 2020-02-23 21:57:28+00:00
Task type: Bug Fix

Issue:
Cannot bind an object property to a component variable in #each if property name is "value"
```javascript
<script>
...
const arr = [{ value: '' }]
</script>

{#each arr as { value }}
     <MyComponent bind:myVariable={value} />
{/each}
```
generates the following :
```javascript
function mycomponent_myVariable_binding(value, value, each_value, each_index) {
	each_value[each_index].value = value;
	$$invalidate(0, arr);
}
```
the first argument is hardcoded to be "value" which makes it impossible to bind it to a property named the same way as the second argument, and although never used, the latter will always be named according to the target property

https://svelte.dev/repl/5527404b82fa4d83a07fecd9c03128df?version=3.18.2


Issue discussion:

Solution patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
 
 ## Unreleased
 
+* Deconflict `value` parameter name used in contextual bindings ([#4445](https://github.com/sveltejs/svelte/issues/4445))
 * Fix dev mode validation of `{#each}` blocks using strings ([#4450](https://github.com/sveltejs/svelte/issues/4450))
 
 ## 3.19.0
diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts
--- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts
+++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts
@@ -332,8 +332,7 @@ export default class InlineComponentWrapper extends Wrapper {
 				contextual_dependencies.push(object.name, property.name);
 			}
 
-			const value = block.get_unique_name('value');
-			const params: any[] = [value];
+			const params = [x`#value`];
 			if (contextual_dependencies.length > 0) {
 				const args = [];
 
@@ -349,23 +348,23 @@ export default class InlineComponentWrapper extends Wrapper {
 
 
 				block.chunks.init.push(b`
-					function ${id}(${value}) {
-						${callee}.call(null, ${value}, ${args});
+					function ${id}(#value) {
+						${callee}.call(null, #value, ${args});
 					}
 				`);
 
 				block.maintain_context = true; // TODO put this somewhere more logical
 			} else {
 				block.chunks.init.push(b`
-					function ${id}(${value}) {
-						${callee}.call(null, ${value});
+					function ${id}(#value) {
+						${callee}.call(null, #value);
 					}
 				`);
 			}
 
 			const body = b`
 				function ${id}(${params}) {
-					${lhs} = ${value};
+					${lhs} = #value;
 					${renderer.invalidate(dependencies[0])};
 				}
 			`;


Test patch:
diff --git a/test/runtime/samples/deconflict-contextual-bind/Widget.svelte b/test/runtime/samples/deconflict-contextual-bind/Widget.svelte
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/deconflict-contextual-bind/Widget.svelte
@@ -0,0 +1,3 @@
+<script>
+	export let prop;
+</script>
diff --git a/test/runtime/samples/deconflict-contextual-bind/_config.js b/test/runtime/samples/deconflict-contextual-bind/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/deconflict-contextual-bind/_config.js
@@ -0,0 +1,3 @@
+export default {
+	preserveIdentifiers: true
+};
diff --git a/test/runtime/samples/deconflict-contextual-bind/main.svelte b/test/runtime/samples/deconflict-contextual-bind/main.svelte
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/deconflict-contextual-bind/main.svelte
@@ -0,0 +1,8 @@
+<script>
+	import Widget from './Widget.svelte';
+	const values = ['foo', 'bar'];
+</script>
+
+{#each values as value}
+	<Widget bind:value/>
+{/each}