Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions pxtblocks/compiler/typeChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ export function returnType(e: Environment, b: Blockly.Block): Point {
return find(b.p);
}

if (b.type == "variables_get")
if (b.type == "variables_get" || b.type == "variables_get_reporter")
return find(lookup(e, b, b.getField("VAR").getText()).type);

if (b.type == "function_call_output") {
Expand Down Expand Up @@ -493,16 +493,20 @@ function getReturnTypeOfFunctionCall(e: Environment, call: Blockly.Block) {
// Basic type unification routine; easy, because there's no structural types.
// FIXME: Generics are not supported
function unify(t1: string, t2: string) {
if (t1 == null || t1 === "Array" && isArrayType(t2))
if (t1 == null || isNullishType(t1) || t1 === "Array" && isArrayType(t2))
return t2;
else if (t2 == null || t2 === "Array" && isArrayType(t1))
else if (t2 == null || isNullishType(t2) || t2 === "Array" && isArrayType(t1))
return t1;
else if (t1 == t2)
return t1;
else
throw new Error("cannot mix " + t1 + " with " + t2);
}

function isNullishType(type: string) {
return type === "null" || type === "undefined";
}

function isArrayType(type: string) {
return type && (type.indexOf("[]") !== -1 || type == "Array");
}
Expand Down
14 changes: 13 additions & 1 deletion pxtlib/music.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,20 @@ namespace pxt.assets.music {
}

export function decodeSongFromHex(hex: string) {
const bytes = pxt.U.fromHex(hex);
let isBase64 = false;
for (let i = 0; i < hex.length; i++) {
const c = hex[i];
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
isBase64 = true;
break;
}
}

if (isBase64) {
return decodeSong(pxt.Util.stringToUint8Array(atob(hex)));
}

const bytes = pxt.U.fromHex(hex);
return decodeSong(bytes);
}

Expand Down
5 changes: 3 additions & 2 deletions pxtsim/sound/audioSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ namespace pxsim.AudioContextManager {
static activeSources: AudioSource[] = [];

static stopAll() {
for (const source of AudioSource.activeSources) {
const activeSources = AudioSource.activeSources;
AudioSource.activeSources = [];
for (const source of activeSources) {
source.dispose();
}
AudioSource.activeSources = [];
}

protected vca: GainNode;
Expand Down
26 changes: 26 additions & 0 deletions tests/blocklycompiler-test/baselines/function_nullish_return.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
function sprite_first () {
for (let localSprite1 of testTypes.allSprites()) {
localSprite1.setPosition(0, 0)
return localSprite1
}
return testTypes.undefinedValue()
}
function undefined_first () {
if (true) {
return testTypes.undefinedValue()
}
for (let localSprite2 of testTypes.allSprites()) {
localSprite2.setPosition(0, 0)
return localSprite2
}
}
let undefinedFirst: Sprite = null
let spriteFirst: Sprite = null
let spriteFirstReferenced = spriteFirst == spriteFirst
let undefinedFirstReferenced = undefinedFirst == undefinedFirst
spriteFirst = sprite_first()
undefinedFirst = undefined_first()
game.onUpdate(function () {
spriteFirst = sprite_first()
undefinedFirst = undefined_first()
})
209 changes: 209 additions & 0 deletions tests/blocklycompiler-test/cases/function_nullish_return.blocks
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
<xml xmlns="https://developers.google.com/blockly/xml">
<variables>
<variable id="spriteFirst">spriteFirst</variable>
<variable id="undefinedFirst">undefinedFirst</variable>
<variable id="spriteFirstReferenced">spriteFirstReferenced</variable>
<variable id="undefinedFirstReferenced">undefinedFirstReferenced</variable>
<variable id="localSprite1">localSprite1</variable>
<variable id="localSprite2">localSprite2</variable>
</variables>
<block type="pxt-on-start" x="0" y="0">
<statement name="HANDLER">
<block type="variables_set">
<field name="VAR" id="spriteFirstReferenced">spriteFirstReferenced</field>
<value name="VALUE">
<block type="logic_compare">
<field name="OP">EQ</field>
<value name="A">
<block type="variables_get">
<field name="VAR" id="spriteFirst">spriteFirst</field>
</block>
</value>
<value name="B">
<block type="variables_get">
<field name="VAR" id="spriteFirst">spriteFirst</field>
</block>
</value>
</block>
</value>
<next>
<block type="variables_set">
<field name="VAR" id="undefinedFirstReferenced">undefinedFirstReferenced</field>
<value name="VALUE">
<block type="logic_compare">
<field name="OP">EQ</field>
<value name="A">
<block type="variables_get">
<field name="VAR" id="undefinedFirst">undefinedFirst</field>
</block>
</value>
<value name="B">
<block type="variables_get">
<field name="VAR" id="undefinedFirst">undefinedFirst</field>
</block>
</value>
</block>
</value>
<next>
<block type="variables_set">
<field name="VAR" id="spriteFirst">spriteFirst</field>
<value name="VALUE">
<block type="function_call_output">
<mutation name="sprite_first" functionid="sprite-first-function" />
</block>
</value>
<next>
<block type="variables_set">
<field name="VAR" id="undefinedFirst">undefinedFirst</field>
<value name="VALUE">
<block type="function_call_output">
<mutation name="undefined_first" functionid="undefined-first-function" />
</block>
</value>
</block>
</next>
</block>
</next>
</block>
</next>
</block>
</statement>
</block>
<block type="gameupdate" x="0" y="180">
<statement name="HANDLER">
<block type="variables_set">
<field name="VAR" id="spriteFirst">spriteFirst</field>
<value name="VALUE">
<block type="function_call_output">
<mutation name="sprite_first" functionid="sprite-first-function" />
</block>
</value>
<next>
<block type="variables_set">
<field name="VAR" id="undefinedFirst">undefinedFirst</field>
<value name="VALUE">
<block type="function_call_output">
<mutation name="undefined_first" functionid="undefined-first-function" />
</block>
</value>
</block>
</next>
</block>
</statement>
</block>
<block type="function_definition" x="400" y="0">
<mutation name="sprite_first" functionid="sprite-first-function" />
<field name="function_name">sprite_first</field>
<statement name="STACK">
<block type="pxt_controls_for_of">
<value name="VAR">
<block type="variables_get_reporter" deletable="false">
<field name="VAR" id="localSprite1">localSprite1</field>
</block>
</value>
<value name="LIST">
<block type="test_all_sprites" />
</value>
<statement name="DO">
<block type="spritesetpos">
<value name="sprite">
<block type="variables_get_reporter">
<field name="VAR" id="localSprite1">localSprite1</field>
</block>
</value>
<value name="x">
<shadow type="math_number">
<field name="NUM">0</field>
</shadow>
</value>
<value name="y">
<shadow type="math_number">
<field name="NUM">0</field>
</shadow>
</value>
<next>
<block type="function_return">
<mutation xmlns="http://www.w3.org/1999/xhtml" no_return_value="false" />
<value name="RETURN_VALUE">
<block type="variables_get_reporter">
<field name="VAR" id="localSprite1">localSprite1</field>
</block>
</value>
</block>
</next>
</block>
</statement>
<next>
<block type="function_return">
<mutation xmlns="http://www.w3.org/1999/xhtml" no_return_value="false" />
<value name="RETURN_VALUE">
<block type="test_undefined_value" />
</value>
</block>
</next>
</block>
</statement>
</block>
<block type="function_definition" x="400" y="300">
<mutation name="undefined_first" functionid="undefined-first-function" />
<field name="function_name">undefined_first</field>
<statement name="STACK">
<block type="controls_if">
<value name="IF0">
<shadow type="logic_boolean">
<field name="BOOL">TRUE</field>
</shadow>
</value>
<statement name="DO0">
<block type="function_return">
<mutation xmlns="http://www.w3.org/1999/xhtml" no_return_value="false" />
<value name="RETURN_VALUE">
<block type="test_undefined_value" />
</value>
</block>
</statement>
<next>
<block type="pxt_controls_for_of">
<value name="VAR">
<block type="variables_get_reporter" deletable="false">
<field name="VAR" id="localSprite2">localSprite2</field>
</block>
</value>
<value name="LIST">
<block type="test_all_sprites" />
</value>
<statement name="DO">
<block type="spritesetpos">
<value name="sprite">
<block type="variables_get_reporter">
<field name="VAR" id="localSprite2">localSprite2</field>
</block>
</value>
<value name="x">
<shadow type="math_number">
<field name="NUM">0</field>
</shadow>
</value>
<value name="y">
<shadow type="math_number">
<field name="NUM">0</field>
</shadow>
</value>
<next>
<block type="function_return">
<mutation xmlns="http://www.w3.org/1999/xhtml" no_return_value="false" />
<value name="RETURN_VALUE">
<block type="variables_get_reporter">
<field name="VAR" id="localSprite2">localSprite2</field>
</block>
</value>
</block>
</next>
</block>
</statement>
</block>
</next>
</block>
</statement>
</block>
</xml>
12 changes: 12 additions & 0 deletions tests/blocklycompiler-test/test-library/spritekind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ class Sprite {
}
}

namespace testTypes {
//% blockId=test_all_sprites block="all sprites"
export function allSprites(): Sprite[] {
return [];
}

//% blockId=test_undefined_value block="undefined"
export function undefinedValue(): undefined {
return undefined;
}
}

//% blockNamespace="statusbars"
//% blockGap=8
class StatusBarSprite extends Sprite {
Expand Down
4 changes: 4 additions & 0 deletions tests/blocklycompiler-test/test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,10 @@ describe("blockly compiler", function () {
blockTestAsync("function_output").then(done, done);
});

it("should ignore nullish types when inferring function return types", (done: () => void) => {
blockTestAsync("function_nullish_return").then(done, done);
});

it("should output a return type for recursive functions", (done: () => void) => {
blockTestAsync("function_recursion").then(done, done);
});
Expand Down
1 change: 1 addition & 0 deletions theme/music-editor/MusicEditor.less
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@import "Track";
@import "TrackSelector";
@import "Workspace";
@import "gallery";

@music-editor-header-color: #e30fc0; // Matches block color
@music-editor-header-border-color: #c10da3; // Matches block color
Expand Down
Loading
Loading