separate reassignment from mutation

pull/12843/head
Rich Harris 2 years ago
parent f12e8b2c49
commit e53df9c37d

@ -331,10 +331,7 @@ const instance_script = {
const binding = /** @type {Compiler.Binding} */ (state.scope.get(declarator.id.name));
if (
state.analysis.uses_props &&
(declarator.init || binding.mutated || binding.reassigned)
) {
if (state.analysis.uses_props && (declarator.init || binding.updated)) {
throw new Error(
'$$props is used together with named props in a way that cannot be automatically migrated.'
);
@ -350,7 +347,7 @@ const instance_script = {
)
: '',
optional: !!declarator.init,
bindable: binding.mutated || binding.reassigned,
bindable: binding.updated,
...extract_type_and_comment(declarator, state.str, path)
});
state.props_insertion_point = /** @type {number} */ (declarator.end);

@ -458,7 +458,7 @@ export function analyze_component(root, source, options) {
for (const { node, path } of binding.references) {
if (node === binding.node) continue;
if (binding.mutated) {
if (binding.updated) {
if (
path[path.length - 1].type === 'StyleDirective' ||
path.some((node) => node.type === 'Fragment') ||
@ -477,7 +477,7 @@ export function analyze_component(root, source, options) {
const scope = /** @type {Scope} */ (template.scopes.get(node));
for (const binding of scope.declarations.values()) {
if (binding.mutated) {
if (binding.updated) {
const state = { scope: /** @type {Scope} */ (scope.parent), scopes: template.scopes };
walk(node.expression, state, {
@ -491,6 +491,7 @@ export function analyze_component(root, source, options) {
if (binding && binding.kind === 'normal') {
binding.kind = 'state';
binding.mutated = binding.updated = true;
}
}
}

@ -134,7 +134,7 @@ function get_delegated_event(event_name, handler, context) {
return unhoisted;
}
if (binding !== null && binding.initial !== null && !binding.mutated && !binding.is_called) {
if (binding !== null && binding.initial !== null && !binding.updated && !binding.is_called) {
const binding_type = binding.initial.type;
if (
@ -188,7 +188,7 @@ function get_delegated_event(event_name, handler, context) {
(((!context.state.analysis.runes && binding.kind === 'each') ||
// or any normal not reactive bindings that are mutated.
binding.kind === 'normal') &&
binding.mutated))
binding.updated))
) {
return unhoisted;
}

@ -39,7 +39,7 @@ export function BindDirective(node, context) {
binding.kind !== 'bindable_prop' &&
binding.kind !== 'each' &&
binding.kind !== 'store_sub' &&
!binding.mutated))
!binding.updated)) // TODO wut?
) {
e.bind_invalid_value(node.expression);
}

@ -17,7 +17,7 @@ export function ExportSpecifier(node, context) {
});
const binding = context.state.scope.get(node.local.name);
if (binding) binding.reassigned = true;
if (binding) binding.reassigned = binding.updated = true;
}
} else {
validate_export(node, context.state.scope, node.local.name);

@ -235,7 +235,7 @@ export function is_prop_source(binding, state) {
binding.initial ||
// Until legacy mode is gone, we also need to use the prop source when only mutated is true,
// because the parent could be a legacy component which needs coarse-grained reactivity
binding.mutated)
binding.updated)
);
}

@ -685,9 +685,13 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
const binding = left && scope.get(left.name);
if (binding !== null && left !== binding.node) {
// TODO we should probably distinguish between these?
binding.mutated = true;
binding.reassigned ||= left === expression;
binding.updated = true;
if (left === expression) {
binding.reassigned = true;
} else {
binding.mutated = true;
}
}
}
}

@ -300,6 +300,8 @@ export interface Binding {
references: { node: Identifier; path: SvelteNode[] }[];
mutated: boolean;
reassigned: boolean;
/** `true` if mutated _or_ reassigned */
updated: boolean;
scope: Scope;
/** For `legacy_reactive`: its reactive dependencies */
legacy_dependencies: Binding[];

Loading…
Cancel
Save