/** * What a scope holds: the record one name resolves to, and the facts flow * analysis writes onto it. * * D114 R1d: `Binding`, `MemberNarrowing`, `PendingScopeDeclaration` and * `MutableCellTarget` were declared inside `analyzer.ts` and read by nothing * else, because nothing else existed. The flow cluster under `./flow/` is the * heaviest reader of all four — a narrowing writes a `Binding`, a member fact * is a `MemberNarrowing` — so they move to the module that names the concept * rather than to the one that happened to hold it. `analyzer.ts` imports them * back, and the `protected` signatures that mention `Binding` are unchanged. */ import { type BindingPattern, type Expression, type FunctionDeclaration, type Statement, type TypeParameterDeclaration } from "../ast.ts"; import { type Diagnostic, type DiagnosticFix } from "../diagnostic.ts"; import { type PermanentNamespaceImports } from "./retired-imports.ts"; import { type LoweringRecorder } from "./lowering-recorder.ts"; import { NearestNameRoster } from "./nearest-names.ts"; import { type Span } from "../source.ts"; import { type ValueType } from "../types.ts"; /** * The mutable binding an assignment writes into, for the one refusal whose fix * lives on the declaration line rather than the assignment line. See * `enumSingletonCellGuidance`. */ export interface MutableCellTarget { readonly name: string; readonly keyword: "let" | "state"; } export interface Binding { readonly mutable: boolean; /** 由普通 `const` 变量声明拥有的一次性值副本;参数、导入和响应式绑定不具备。 */ stableOptionalCopy?: boolean; type: ValueType; declaredType: ValueType; storageType: ValueType; readonly storageBinding?: Binding; readonly span: Span; narrowingFrame: number | null; /** * The scope depth this binding was created at. A flow snapshot only visits * bindings whose facts have actually moved, and this is how the set of those * is emptied again when the scope holding them exits. */ readonly flowScope?: number; /** * D44 rule 71: true while the active narrowing was established by an * assignment (or a declaration initializer) rather than a check. Only * meaningful when narrowingFrame is not null. Assigned facts refine reads; * equality tests still judge the declared domain (storageType). */ assignedFact?: boolean; reactiveKind?: "state" | "prop"; /** * D51 rule 101: the binding holds — or carries — a resource this scope owns * and releases at its exit. `handle` is the `using` name to blame, and * `depth` is the scope nesting level that releases it, so a store into any * shallower binding is a store into something that outlives the release. */ ownedResource?: { readonly handle: string; readonly depth: number; }; } export interface MemberNarrowing { readonly type: ValueType; readonly frame: number; /** * D44 rule 71: true when the fact was established by an assignment rather * than a check. Assigned facts refine reads, but an equality test still * asks about the declared domain, so `x == null` after `x = "a"` stays a * real question instead of a rejected constant. */ readonly assigned?: boolean; /** The declared type of the location an assigned fact refines (its test-domain). */ readonly domain?: ValueType; } export interface PendingScopeDeclaration { readonly span: Span; readonly loopHead: boolean; } /** * The scope chain as it stood at one point, read back on demand. Flattening * every live scope into a fresh Map made each block, loop and match cost * O(names in the module), which is most of what made whole-module analysis * quadratic in module size. The depth is enough: scopes are a stack, so the * scopes below a construct's own are exactly the ones that were there, and * nothing adds a name to them while the construct is being analyzed. */ export type VisibleScopeDepth = number; /** * A narrowing roster is keyed by binding name, and a member fact's key is a * dotted access path. This prefix keeps the two key spaces apart in one map; * it is a NUL byte, which no source identifier can contain. */ export declare const memberNarrowingPrefix = "\0member:"; /** * The declaration positions that also introduce a *type* name, named for the * one sentence that refuses a built-in spelling in any of them. */ export type BuiltinTypeNamePosition = "type" | "class" | "enum" | "extern class" | "imported name" | "import alias" | "type parameter"; export declare const builtinTypeNames: Set; /** * D72 rule 186 over the Core roster, and charter §5 and §7: the built-in type * names are reserved. A user declaration spelled with one used to be accepted * where it was written and then lose at every use — `type Duration:` compiled, * and `const d: Duration = {label: "a"}` was told it could not assign to a type * the author had just declared. Half the roster lost the other way and shadowed * the built-in for bare uses only, so `type List:` left `List` meaning the user * record and `List` on the next line still meaning the built-in. D51 * rule 109 puts the refusal at the declaration, the only place a rename is * cheap. * * Two refusals already say this sentence about smaller rosters: * `rejectReservedTypeNames` for the three type-parameter bounds (D51 rule 109, * VEL4021) and `rejectWebOwnedTypeNames` in packages/web/src/analyzer.ts for * the Web type names (VEL5065). This is the same sentence over Core's own * roster, so all three read alike. Before it, only `number`, `Set`, `Map` and * `Promise` were refused, and only incidentally — they are *also* reserved Core * bindings — so one rule reached four of fourteen names by accident. * * Unlike its two siblings this is asked from `declareBinding` rather than from * a pass over `program.body`, because those four names carry both answers and * only the declaration site can decide which sentence the author earns: the * reserved-binding report and this one are the two arms of one `if`, so a name * that is a built-in type and a reserved Core binding is still one mistake with * one report. The roster is `builtinTypeNames`, which `isDeclaredTypeName` * already reads, so a built-in added there is covered here without a new * branch. */ export declare function builtinTypeNameDeclarationMessage(name: string, position: BuiltinTypeNamePosition): string; /** * Everything the scope stack asks of the analyzer that hosts it. */ export interface ScopeStackHost { readonly diagnostics: Diagnostic[]; expandAliases(type: ValueType, seen?: ReadonlySet): ValueType; readonly extensionGlobals: Map; readonly extensionReservedBindings: Set; fieldsOf(identity: string): ReadonlyMap | null; readonly flowFrameDepth: number; functionResultKey(statement: Pick): string; readonly functionResultKeys: Map; functionType(statement: FunctionDeclaration, classParameters?: readonly TypeParameterDeclaration[]): ValueType; readonly globalGuidance: Map; readonly importBindings: ReadonlyMap; readonly importedBindingOrigins: Map; readonly lowering: LoweringRecorder; readonly modulePath: string | null; readonly namespaceImports: PermanentNamespaceImports; /** * CO-I1: the import specifiers that repeat an export this module already * binds, by span identity, recorded by `ModuleImports.registerImportSpecifiers` * before anything is declared. A collision between two imports is only a * *duplicate* when both name the same export of the same module; two * different exports that happen to share a local name still answer with an * alias, which is why this cannot be decided from the colliding name alone. */ readonly duplicateExportSpecifiers: ReadonlySet; /** CO-I1: the export each named import specifier binds, by span identity. */ readonly importSpecifierExportNames: ReadonlyMap; readonly predeclared: WeakSet; prescanExtensionScopeDeclaration(_statement: Statement): { readonly name: string; readonly span: Span; } | null; readonlyDataViewOf(type: ValueType): ValueType; readonlyFieldsOf(identity: string): ReadonlySet | null; recordSemanticBinding(key: string, type: ValueType): void; readonly scopedGlobalGuidance: Map>; readonly semanticBindingEntryOwners: Map; typeError(message: string, errorSpan: Span, fix?: DiagnosticFix): void; } /** * The scope stack itself: the chain of name-to-binding maps a lookup walks, the * declarations a scope has promised but not yet made, the "did you mean" roster, * and the rules a declaration has to pass to enter a scope. * * D114 R1d: `declareBinding`, `declarePattern`, `lookup` and * `prescanScopeDeclarations` stay `protected` on `Analyzer` and forward here; * `enterScope` and `exitScope` do the same, pushing this stack and the flow * cluster's own in the order they were pushed before. */ export declare class ScopeStack { private readonly host; readonly scopes: Map[]; readonly pendingScopeDeclarations: Map[]; /** The "did you mean" roster, and the names each scope depth contributed to it. */ readonly nearestNames: NearestNameRoster; readonly scopedNames: string[][]; nearestNamesSeeded: boolean; /** Every name this module declares anywhere, so a rewrite can prove it collides with nothing. */ readonly declaredNames: Set; /** * The type names a more specific refusal has already answered for in this * module. The reserved-name rule is stated over three rosters — Core's * built-in type names here, the three type-parameter bounds in * `rejectReservedTypeNames`, and the Web extension's own names in * `rejectWebOwnedTypeNames` — and two of them overlap this one. `class Text:` * earned the bound's sentence *and* "reserved Core binding"; `type Duration:` * in a Web module earned the Web sentence *and* Core's. One mistake earns one * report, and the sentence that survives is the one that says why the name is * taken. */ readonly refusedTypeNames: Set; /** * D114 item 9: the guided spellings a declaring position has already refused * in this module, by name. `def object()` is refused where the `def` is read * and `class object:` where the `class` is; both then reach `declareBinding`, * and one mistake earns one report. */ readonly refusedGuidedNames: Set; readonly reportedShadowedReads: Set; constructor(host: ScopeStackHost); enterScope(): void; exitScope(): void; declareBinding(name: string, mutable: boolean, type: ValueType, declarationSpan: Span, internal?: boolean, declaredType?: ValueType, importSource?: string, /** * Set when this binding also introduces a *type* name, which is the one * question `builtinTypeNameDeclarationMessage` answers. A `const` or a * parameter leaves it unset: naming a local `List` shadows the built-in * value, but `List` in a type position still means the built-in there, so * the reserved-type-name rule has nothing to say about it. */ typeNamePosition?: BuiltinTypeNamePosition): void; /** * Why this spelling is not available as a binding, or null when it is. * `invalid`, `keyword` and `source` are absent because the lexer already * reported the word the author wrote. */ private reservedBindingMessage; /** * A `type`, `class` or `enum` name. Every one of them declares a binding and * a type name at once, so they ask `declareBinding` the reserved-type-name * question here rather than each repeating the argument list that carries it. */ declareTypeNameBinding(name: string, type: ValueType, declarationSpan: Span, position: BuiltinTypeNamePosition): void; /** * D114 item 9: refuses `object`, `Object` or `Callable` standing in a * declaring position, and answers whether it did. * * The value positions charter §5 names — a `def` and a `const` — reach * `declareBinding` with no position word of their own, so they call this * where they read the declaration and `declareBinding` then stays silent. */ refuseGuidedDeclarationName(name: string, position: string, declarationSpan: Span): boolean; declarePattern(pattern: BindingPattern, mutable: boolean, type: ValueType, declaredType?: ValueType): void; collectPatternNames(pattern: BindingPattern, add: (name: string) => void): void; checkShadowedRead(name: string, span: Span): void; validateKnownBindingShape(pattern: BindingPattern, value: Expression): void; /** * D90 (coherence): the one report an unresolved name earns, wherever it was * written. A reserved global names the module that replaced it, a foreign * builtin with no successor stops at the bare message rather than guessing, * and everything else may carry the nearest visible name. Both unresolved- * name sites reach this, because `exports = {run: run}` is the same mistake * as `const value = exports` and used to earn a strictly worse answer for * standing on the left of the `=`. */ reportUnresolvedName(name: string, span: Span): void; nearestVisibleBindingName(name: string): string | null; /** Files a scope's name in the "did you mean" roster and takes it back out when the scope exits. */ recordScopedName(name: string): void; builtin(name: string): Binding | null; prescanScopeDeclarations(statements: readonly Statement[]): void; /** * Marks a declared type name as already refused by a rule whose sentence says * why the name is taken, so `declareBinding` leaves the general one unsaid. * The extension calls it from its own roster refusal, which is what lets the * Web analyzer take precedence here without either side learning the other's * roster. */ markTypeNameRefused(name: string): void; lookup(name: string): Binding | null; isTopLevelScope(): boolean; /** * The guidance a reserved global earns where it was written. A module path * suffix selects the door that is actually open there before the module-wide * answer applies. */ guidanceForGlobal(name: string): string | undefined; } //# sourceMappingURL=scopes.d.ts.map