fix: prevent false positive ownership warning (#11490)

fixes #11483
We need to keep track of the component function similar to how we keep track of the component context, so that effects etc have the correct one associated
pull/11474/head
Simon H 1 year ago committed by GitHub
parent 3e1f82b8c4
commit d86b05279f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"svelte": patch
---
fix: prevent false positive ownership warning

@ -2,7 +2,7 @@
import { STATE_SYMBOL } from '../constants.js'; import { STATE_SYMBOL } from '../constants.js';
import { render_effect, user_pre_effect } from '../reactivity/effects.js'; import { render_effect, user_pre_effect } from '../reactivity/effects.js';
import { dev_current_component_function, set_dev_current_component_function } from '../runtime.js'; import { dev_current_component_function } from '../runtime.js';
import { get_prototype_of } from '../utils.js'; import { get_prototype_of } from '../utils.js';
import * as w from '../warnings.js'; import * as w from '../warnings.js';
@ -128,12 +128,8 @@ export function add_owner(object, owner, global = false) {
* @param {any} Component * @param {any} Component
*/ */
export function add_owner_effect(get_object, Component) { export function add_owner_effect(get_object, Component) {
var component = dev_current_component_function;
user_pre_effect(() => { user_pre_effect(() => {
var prev = dev_current_component_function;
set_dev_current_component_function(component);
add_owner(get_object(), Component); add_owner(get_object(), Component);
set_dev_current_component_function(prev);
}); });
} }

@ -4,10 +4,12 @@ import {
flush_sync, flush_sync,
set_current_component_context, set_current_component_context,
set_current_effect, set_current_effect,
set_current_reaction set_current_reaction,
set_dev_current_component_function
} from '../../runtime.js'; } from '../../runtime.js';
import { block, branch, destroy_effect, pause_effect } from '../../reactivity/effects.js'; import { block, branch, destroy_effect, pause_effect } from '../../reactivity/effects.js';
import { INERT } from '../../constants.js'; import { INERT } from '../../constants.js';
import { DEV } from 'esm-env';
/** /**
* @template V * @template V
@ -20,6 +22,11 @@ import { INERT } from '../../constants.js';
*/ */
export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) { export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) {
const component_context = current_component_context; const component_context = current_component_context;
/** @type {any} */
let component_function;
if (DEV) {
component_function = component_context?.function ?? null;
}
/** @type {any} */ /** @type {any} */
let input; let input;
@ -41,7 +48,13 @@ export function await_block(anchor, get_input, pending_fn, then_fn, catch_fn) {
set_current_effect(effect); set_current_effect(effect);
set_current_reaction(effect); // TODO do we need both? set_current_reaction(effect); // TODO do we need both?
set_current_component_context(component_context); set_current_component_context(component_context);
if (DEV) {
set_dev_current_component_function(component_function);
}
var e = branch(() => fn(anchor, value)); var e = branch(() => fn(anchor, value));
if (DEV) {
set_dev_current_component_function(null);
}
set_current_component_context(null); set_current_component_context(null);
set_current_reaction(null); set_current_reaction(null);
set_current_effect(null); set_current_effect(null);

@ -4,6 +4,7 @@ import {
current_effect, current_effect,
current_reaction, current_reaction,
destroy_effect_children, destroy_effect_children,
dev_current_component_function,
execute_effect, execute_effect,
get, get,
is_destroying_effect, is_destroying_effect,
@ -30,6 +31,7 @@ import {
import { set } from './sources.js'; import { set } from './sources.js';
import { remove } from '../dom/reconciler.js'; import { remove } from '../dom/reconciler.js';
import * as e from '../errors.js'; import * as e from '../errors.js';
import { DEV } from 'esm-env';
/** /**
* @param {import('#client').Effect | null} effect * @param {import('#client').Effect | null} effect
@ -86,6 +88,10 @@ function create_effect(type, fn, sync) {
transitions: null transitions: null
}; };
if (DEV) {
effect.component_function = dev_current_component_function;
}
if (current_reaction !== null && !is_root) { if (current_reaction !== null && !is_root) {
push_effect(effect, current_reaction); push_effect(effect, current_reaction);
} }

@ -49,6 +49,8 @@ export interface Effect extends Reaction {
prev: null | Effect; prev: null | Effect;
/** Next sibling child effect created inside the parent signal */ /** Next sibling child effect created inside the parent signal */
next: null | Effect; next: null | Effect;
/** Dev only */
component_function?: any;
} }
export interface ValueDebug<V = unknown> extends Value<V> { export interface ValueDebug<V = unknown> extends Value<V> {

@ -113,9 +113,6 @@ export let current_component_context = null;
/** @param {import('#client').ComponentContext | null} context */ /** @param {import('#client').ComponentContext | null} context */
export function set_current_component_context(context) { export function set_current_component_context(context) {
current_component_context = context; current_component_context = context;
if (DEV) {
dev_current_component_function = context?.function;
}
} }
/** /**
@ -420,7 +417,12 @@ export function execute_effect(effect) {
var previous_component_context = current_component_context; var previous_component_context = current_component_context;
current_effect = effect; current_effect = effect;
set_current_component_context(component_context); current_component_context = component_context;
if (DEV) {
var previous_component_fn = dev_current_component_function;
dev_current_component_function = effect.component_function;
}
try { try {
if ((flags & BLOCK_EFFECT) === 0) { if ((flags & BLOCK_EFFECT) === 0) {
@ -432,7 +434,11 @@ export function execute_effect(effect) {
effect.teardown = typeof teardown === 'function' ? teardown : null; effect.teardown = typeof teardown === 'function' ? teardown : null;
} finally { } finally {
current_effect = previous_effect; current_effect = previous_effect;
set_current_component_context(previous_component_context); current_component_context = previous_component_context;
if (DEV) {
dev_current_component_function = previous_component_fn;
}
} }
} }
@ -1108,7 +1114,10 @@ export function pop(component) {
effect(effects[i]); effect(effects[i]);
} }
} }
set_current_component_context(context_stack_item.p); current_component_context = context_stack_item.p;
if (DEV) {
dev_current_component_function = context_stack_item.p?.function ?? null;
}
context_stack_item.m = true; context_stack_item.m = true;
} }
// Micro-optimization: Don't set .a above to the empty object // Micro-optimization: Don't set .a above to the empty object

@ -0,0 +1,7 @@
<script>
let { object = $bindable() } = $props();
</script>
<button onclick={() => object.count += 1}>
clicks: {object.count}
</button>

@ -0,0 +1,5 @@
<script>
let { children } = $props();
</script>
{@render children?.()}

@ -0,0 +1,11 @@
import { test } from '../../test';
export default test({
html: `<button>clicks: 0</button>`,
compileOptions: {
dev: true
},
warnings: []
});

@ -0,0 +1,14 @@
<script>
import Outer from './Outer.svelte';
import Inner from './Inner.svelte';
let object = $state({ count: 0 });
let test = $state(true);
</script>
<Outer>
<!-- check that render effects inside slotted content doesn't mess with ownership validation -->
{#if test}
<Inner bind:object />
{/if}
</Outer>
Loading…
Cancel
Save