fable-compiler / Fable

F# to JavaScript, TypeScript, Python, Rust and Dart Compiler
http://fable.io/
MIT License
2.93k stars 301 forks source link

error when aliasing a Global value #3927

Open joprice opened 1 month ago

joprice commented 1 month ago

Description

Creating a top-level binding to a Global value with the same name causes a reference error

Uncaught ReferenceError: Cannot access 'self' before initialization

Repro code

open Fable.Core

type Exports =
    [<Global>]
    static member self: obj = nativeOnly
    static member x: int = 1

// this line generates: export const self = self;
let self = Exports.self
// this line generates: const self = self;
// let private  self = Exports.self

https://fable.io/repl/#?code=PYBwpgdgBAYghgIwDZgHQGFgCcwChcAuAnuFAKIAeI2BAzlALy5QtQDaAPAOJLAJxIAfAF1mrWgTgEAlgGMoAWzAKEYLFFpgkAMwBcUPgCtGUCFOkA3MAHkISImJYTz8pSrVQK+6RAImAjPgofpo6JpTUWHSoodq4wVAA+rHhVDS0MVraQA&html=Q&css=Q

Expected and actual results

Ideally, this situation would either be a compiler error or create an shadowed aliased value. In local scopes, a similar reference is aliased locally:

let y () = 
  let self = Exports.self
  self
export function y() {
    const self_1 = self;
    return self_1;
}

For public toplevel fields, which are automatically exported, I'm not sure how it should behave.

Related information

MangelMaxime commented 1 month ago

I don't think there is something we can do about this one because we can't garante that there is no self variable available in the runtime.

I suppose we could argue that const self = self will always fails in JavaScript because of Uncaught SyntaxError: Identifier 'self' has already been declared.

And that let self = self can sometimes works in JavaScript, if self is available globally before.

For me this issue, ask Fable to do more than verifying F# and lean toward JavaScript/TypeScript compiler/runtimes responsibility.