Skip to content

Commit 4ed9e2a

Browse files
mohsen1claude
andcommitted
Complete: Fix global symbol type binding
- Move ValidationError enum outside impl block to fix compilation error - Fix symbol_id type casting (i -> i as u32) for ValidationError fields - Restore proper control flow structure in resolve_identifier_symbol (add missing if/while scope walking loop that was lost in merge) - Add Promise<T> interface to lib.d.ts with full method signatures - Add PromiseConstructor interface with all static methods - Add Awaited<T> type alias for async/await support - Add declare var Promise: PromiseConstructor Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent cfcdaba commit 4ed9e2a

3 files changed

Lines changed: 124 additions & 14 deletions

File tree

tests/lib/lib.d.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,105 @@ interface PromiseLike<T> {
12081208
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): PromiseLike<TResult>;
12091209
}
12101210

1211+
/**
1212+
* Represents the completion of an asynchronous operation
1213+
*/
1214+
interface Promise<T> {
1215+
/**
1216+
* Attaches callbacks for the resolution and/or rejection of the Promise.
1217+
* @param onfulfilled The callback to execute when the Promise is resolved.
1218+
* @param onrejected The callback to execute when the Promise is rejected.
1219+
* @returns A Promise for the completion of which ever callback is executed.
1220+
*/
1221+
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
1222+
1223+
/**
1224+
* Attaches a callback for only the rejection of the Promise.
1225+
* @param onrejected The callback to execute when the Promise is rejected.
1226+
* @returns A Promise for the completion of the callback.
1227+
*/
1228+
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
1229+
1230+
/**
1231+
* Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected).
1232+
* The resolved value cannot be modified from the callback.
1233+
* @param onfinally The callback to execute when the Promise is settled.
1234+
* @returns A Promise for the completion of the callback.
1235+
*/
1236+
finally(onfinally?: (() => void) | undefined | null): Promise<T>;
1237+
}
1238+
1239+
interface PromiseConstructor {
1240+
/**
1241+
* A reference to the prototype.
1242+
*/
1243+
readonly prototype: Promise<any>;
1244+
1245+
/**
1246+
* Creates a new Promise.
1247+
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
1248+
* a resolve callback used to resolve the promise with a value or the result of another promise,
1249+
* and a reject callback used to reject the promise with a provided reason or error.
1250+
*/
1251+
new <T>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
1252+
1253+
/**
1254+
* Creates a Promise that is resolved with an array of results when all of the provided Promises
1255+
* resolve, or rejected when any Promise is rejected.
1256+
* @param values An array of Promises.
1257+
* @returns A new Promise.
1258+
*/
1259+
all<T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]> }>;
1260+
1261+
/**
1262+
* Creates a Promise that is resolved or rejected when any of the provided Promises are resolved
1263+
* or rejected.
1264+
* @param values An array of Promises.
1265+
* @returns A new Promise.
1266+
*/
1267+
race<T extends readonly unknown[] | []>(values: T): Promise<Awaited<T[number]>>;
1268+
1269+
/**
1270+
* Creates a new rejected promise for the provided reason.
1271+
* @param reason The reason the promise was rejected.
1272+
* @returns A new rejected Promise.
1273+
*/
1274+
reject<T = never>(reason?: any): Promise<T>;
1275+
1276+
/**
1277+
* Creates a new resolved promise.
1278+
* @returns A resolved promise.
1279+
*/
1280+
resolve(): Promise<void>;
1281+
1282+
/**
1283+
* Creates a new resolved promise for the provided value.
1284+
* @param value A promise.
1285+
* @returns A promise whose internal state matches the provided promise.
1286+
*/
1287+
resolve<T>(value: T): Promise<Awaited<T>>;
1288+
1289+
/**
1290+
* Creates a new resolved promise for the provided value.
1291+
* @param value A promise.
1292+
* @returns A promise whose internal state matches the provided promise.
1293+
*/
1294+
resolve<T>(value: T | PromiseLike<T>): Promise<Awaited<T>>;
1295+
}
1296+
1297+
declare var Promise: PromiseConstructor;
1298+
1299+
/**
1300+
* Recursively unwraps the "awaited type" of a type. Non-promise "thenables" should resolve to `never`. This emulates the behavior of `await`.
1301+
*/
1302+
type Awaited<T> =
1303+
T extends null | undefined ? T :
1304+
T extends object & { then(onfulfilled: infer F, ...args: infer _): any } ?
1305+
F extends ((value: infer V, ...args: infer _) => any) ?
1306+
Awaited<V> :
1307+
never :
1308+
T;
1309+
12111310
interface ArrayLike<T> {
12121311
length: number;
12131312
[n: number]: T;

wasm/src/thin_binder.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,17 @@ pub struct ThinBinderState {
7777
current_scope_id: ScopeId,
7878
}
7979

80+
/// Validation result describing issues found in the symbol table
81+
#[derive(Debug, Clone, PartialEq)]
82+
pub enum ValidationError {
83+
/// A node->symbol mapping points to a non-existent symbol
84+
BrokenSymbolLink { node_index: u32, symbol_id: u32 },
85+
/// A symbol exists but has no declarations (orphaned)
86+
OrphanedSymbol { symbol_id: u32, name: String },
87+
/// A symbol's value_declaration points to a non-existent node
88+
InvalidValueDeclaration { symbol_id: u32, name: String },
89+
}
90+
8091
impl ThinBinderState {
8192
pub fn new() -> Self {
8293
let mut flow_nodes = FlowNodeArena::new();
@@ -3583,17 +3594,6 @@ impl ThinBinderState {
35833594
self.bind_node(arena, idx);
35843595
}
35853596

3586-
/// Validation result describing issues found in the symbol table
3587-
#[derive(Debug, Clone, PartialEq)]
3588-
pub enum ValidationError {
3589-
/// A node->symbol mapping points to a non-existent symbol
3590-
BrokenSymbolLink { node_index: u32, symbol_id: u32 },
3591-
/// A symbol exists but has no declarations (orphaned)
3592-
OrphanedSymbol { symbol_id: u32, name: String },
3593-
/// A symbol's value_declaration points to a non-existent node
3594-
InvalidValueDeclaration { symbol_id: u32, name: String },
3595-
}
3596-
35973597
/// Run post-binding validation checks on the symbol table.
35983598
/// Returns a list of validation errors found.
35993599
pub fn validate_symbol_table(&self) -> Vec<ValidationError> {
@@ -3613,7 +3613,7 @@ impl ThinBinderState {
36133613
if let Some(sym) = self.symbols.get(sym_id) {
36143614
if sym.declarations.is_empty() {
36153615
errors.push(ValidationError::OrphanedSymbol {
3616-
symbol_id: i,
3616+
symbol_id: i as u32,
36173617
name: sym.escaped_name.clone(),
36183618
});
36193619
}
@@ -3627,7 +3627,7 @@ impl ThinBinderState {
36273627
let has_node_mapping = self.node_symbols.contains_key(&sym.value_declaration.0);
36283628
if !has_node_mapping {
36293629
errors.push(ValidationError::InvalidValueDeclaration {
3630-
symbol_id: i,
3630+
symbol_id: i as u32,
36313631
name: sym.escaped_name.clone(),
36323632
});
36333633
}

wasm/src/thin_checker.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,6 @@ impl<'a> ThinCheckerState<'a> {
297297
let node = self.ctx.arena.get(idx)?;
298298
let name = self.ctx.arena.get_identifier(node)?.escaped_text.as_str();
299299

300-
301300
// Collect lib binders for cross-arena symbol lookup
302301
let lib_binders: Vec<Arc<crate::thin_binder::ThinBinderState>> =
303302
self.ctx.lib_contexts.iter().map(|lc| Arc::clone(&lc.binder)).collect();
@@ -309,6 +308,18 @@ impl<'a> ThinCheckerState<'a> {
309308
name, idx
310309
);
311310
}
311+
312+
if let Some(mut scope_id) = self.find_enclosing_scope(idx) {
313+
let require_export = false;
314+
while !scope_id.is_none() {
315+
if let Some(scope) = self.ctx.binder.scopes.get(scope_id.0 as usize) {
316+
if let Some(sym_id) = scope.table.get(name) {
317+
if let Some(symbol) = self.ctx.binder.get_symbol_with_libs(sym_id, &lib_binders) {
318+
let export_ok = !require_export
319+
|| scope.kind != ContainerKind::Module
320+
|| symbol.is_exported
321+
|| (symbol.flags & symbol_flags::EXPORT_VALUE) != 0;
322+
if export_ok && !Self::is_class_member_symbol(symbol.flags) {
312323
if std::env::var("BIND_DEBUG").is_ok() {
313324
eprintln!("[BIND_RESOLVE] Found '{}' in scope {:?}", name, scope_id);
314325
}

0 commit comments

Comments
 (0)