◆ 実行時に async 関数にラップされる
◆ 変数は関数外でも使えるように宣言がグローバル変数になるように変換される
◆ 構文エラーがあるとラップされないので await は async 関数でしか使えないというエラー
  ◆ 原因と違うエラーメッセージになるのでわかりづらい
  ◆ トップレベル await でこのエラーがでたら何かの構文エラーがある
◆ ラップされると結果表示のために最後が式なら return が追加される
  ◆ if の場合などは追加されないので結果は undefined になる

Chrome の devtools のコンソールの話です

const が再代入できる

const は再代入不可なので このように同じ名前を 2 回使うとエラーになります
空行のところで 1 回エンターが入っています

const value = 1
// undefined

const value = 2
// Uncaught SyntaxError: Identifier 'value' has already been declared
// at <anonymous>:1:1

エラーになるはずなのですが await を使うとなぜかエラーが起きませんでした

await Promise.resolve()
const value = 1
// undefined

await Promise.resolve()
const value = 2
// undefined

別のページにしたりリロードしてやってみても再現します

理由

コンソールではトップレベル await に対応していますが JavaScript 標準の機能ではないので自動で async 関数にラップされて実行されてそうです
それのせいでスコープが別になって再定義にならないように思えます

debugger を使って確認してみましょう

debugger
await Promise.resolve()
const value = 1
(async () => {debugger
await Promise.resolve()
void (value = 1)
})()

下側のブロックは自動で表示される source タブで確認できます
やっぱり async 関数になってますね

ただ 「const value = 1」 が 「void (value = 1)」 に変換されていました
よく考えると const のスコープはその関数の中で終わるので 次の実行にその変数を維持するためにはグローバル変数である必要があります
なのでグローバル変数として代入するために const をはずすように変換されているわけですね

エラーがおかしい

これまでは 2 つの const はそれぞれ別の実行になっていました
1 回の実行にまとめると 1 つの async 関数になって再代入不可のエラーが出そうと思ってましたが const がはずされてるなら普通に動きそうと思って試してみたら

await Promise.resolve()
const value = 1
const value = 2
// Uncaught SyntaxError: await is only valid in async function

await は async 関数でしか使えないという構文エラーです
内部で const が 2 つの時点で構文がエラーになって async 関数にラップする変換は行われず そのまま実行されてるようです
分かりづらいエラーですね
原因は const なのに なぜかトップレベル await が使えない みたいなメッセージになってます

コンソールの最後に評価したもの

おまけで debugger で見れる実際に実行されてるコードをもう少し見てみます

await がなく async でラップされない場合はコードはそのままです

debugger
1 + 1
debugger
1 + 1

ですが async になると最後に評価したものを結果として表示するために return が追加されます

debugger
await Promise.resolve()
1 + 2
(async () => {debugger
await Promise.resolve()
return (1 + 2)

})()

しかし これは最後の場合のみです
if 文などになると return は追加されません

debugger
await Promise.resolve()

if (true) {
1
} else {
2
}
// undefined
(async () => {debugger
await Promise.resolve()

if (true) {
1
} else {
2
}
})()

return がないので返り値は undefined です
async 関数にラップされるからと言ってここで return は使えません

自分で console.log を書いたり 適当な変数に入れて最後にそれにアクセスする必要があります
if に限らず try-catch も同じで 単純に「末尾が式なら return をつける」という処理しかしていないようです

気になったので軽くコードを見てみました

FormatterWorker.preprocessTopLevelAwaitExpressions = function(content) {
let wrapped = '(async () => {' + content + '\n})()';
let root;
let body;
try {
root = acorn.parse(wrapped, {
ecmaVersion: 10
});
body = root.body[0].expression.callee.body;
} catch (e) {
postMessage('');
return;
}

/* 略 */

const last = body.body[body.body.length - 1];
if (last.type === 'ExpressionStatement') {
changes.push({
text: 'return (',
start: last.start,
end: last.start
});
if (wrapped[last.end - 1] !== ';')
changes.push({
text: ')',
start: last.end,
end: last.end
});
else
changes.push({
text: ')',
start: last.end - 1,
end: last.end - 1
});
}
while (changes.length) {
const change = changes.pop();
wrapped = wrapped.substr(0, change.start) + change.text + wrapped.substr(change.end);
}
postMessage(wrapped);
}

acorn でパースして最後が式なら return を追加してますね

devtools 自体の devtools は Ctrl-Shift-I を devtools を使ってるときに入力すると開けます
さらにその devtools にも devtools を開けてよくわからないことになってきます
とりあえず devtools 自体のコードは Chrome だけあれば見れます