Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: AssemblyScript/assemblyscript
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.27.18
Choose a base ref
...
head repository: AssemblyScript/assemblyscript
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.27.19
Choose a head ref
  • 4 commits
  • 13 files changed
  • 2 contributors

Commits on Nov 17, 2023

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    53aab48 View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    5ee17be View commit details
  3. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    41f395a View commit details
  4. fix: string field with false value in asconfig.js (#2802)

    Co-authored-by: Zhenya.Liu <zhenya.liu@partner.bmw.com>
    HerrCai0907 and Zhenya.Liu authored Nov 17, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    5dec4a3 View commit details
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -77,14 +77,15 @@
"build": "node scripts/build",
"watch": "node scripts/build --watch",
"coverage": "npx c8 -- npm test",
"test": "npm run test:parser && npm run test:compiler -- --parallel && npm run test:browser && npm run test:asconfig && npm run test:transform",
"test": "npm run test:parser && npm run test:compiler -- --parallel && npm run test:browser && npm run test:asconfig && npm run test:transform && npm run test:cli",
"test:parser": "node --enable-source-maps tests/parser",
"test:compiler": "node --enable-source-maps --no-warnings tests/compiler",
"test:browser": "node --enable-source-maps tests/browser",
"test:asconfig": "cd tests/asconfig && npm run test",
"test:transform": "npm run test:transform:esm && npm run test:transform:cjs",
"test:transform:esm": "node bin/asc tests/compiler/empty --transform ./tests/transform/index.js --noEmit && node bin/asc tests/compiler/empty --transform ./tests/transform/simple.js --noEmit",
"test:transform:cjs": "node bin/asc tests/compiler/empty --transform ./tests/transform/cjs/index.js --noEmit && node bin/asc tests/compiler/empty --transform ./tests/transform/cjs/simple.js --noEmit",
"test:cli": "node tests/cli/options.js",
"asbuild": "npm run asbuild:debug && npm run asbuild:release",
"asbuild:debug": "node bin/asc --config src/asconfig.json --target debug",
"asbuild:release": "node bin/asc --config src/asconfig.json --target release",
2 changes: 1 addition & 1 deletion src/diagnosticMessages.json
Original file line number Diff line number Diff line change
@@ -151,7 +151,6 @@
"Operator '{0}' cannot be applied to types '{1}' and '{2}'.": 2365,
"A 'super' call must be the first statement in the constructor.": 2376,
"Constructors for derived classes must contain a 'super' call.": 2377,
"Getter and setter accessors do not agree in visibility.": 2379,
"'get' and 'set' accessor must have the same type.": 2380,
"Overload signatures must all be public, private or protected.": 2385,
"Constructor implementation is missing.": 2390,
@@ -200,6 +199,7 @@
"Duplicate property '{0}'.": 2718,
"Property '{0}' is missing in type '{1}' but required in type '{2}'.": 2741,
"Type '{0}' has no call signatures.": 2757,
"Get accessor '{0}' must be at least as accessible as the setter.": 2808,
"This member cannot have an 'override' modifier because it is not declared in the base class '{0}'.": 4117,

"File '{0}' not found.": 6054,
15 changes: 9 additions & 6 deletions src/passes/shadowstack.ts
Original file line number Diff line number Diff line change
@@ -159,18 +159,21 @@ type TempMap = Map<TypeRef,LocalIndex>;

/** Attempts to match the `__tostack(value)` pattern. Returns `value` if a match, otherwise `0`. */
function matchPattern(module: Module, expr: ExpressionRef): ExpressionRef {
if (
let isFound = false;
while (
_BinaryenExpressionGetId(expr) == ExpressionId.Call &&
module.readStringCached(_BinaryenCallGetTarget(expr)) == BuiltinNames.tostack
) {
assert(_BinaryenCallGetNumOperands(expr) == 1);
return _BinaryenCallGetOperandAt(expr, 0);
expr = _BinaryenCallGetOperandAt(expr, 0);
isFound = true;
}
return 0;
if (!isFound) return 0;
return expr;
}

/** Tests whether a `value` matched by `matchTostack` needs a slot. */
function needsSlot(module: Module, value: ExpressionRef): bool {
function needsSlot(value: ExpressionRef): bool {
switch (_BinaryenExpressionGetId(value)) {
// no need to stack null pointers
case ExpressionId.Const: return !isConstZero(value);
@@ -344,7 +347,7 @@ export class ShadowStackPass extends Pass {
let operand = operands[i];
let match = matchPattern(module, operand);
if (!match) continue;
if (!needsSlot(module, match)) {
if (!needsSlot(match)) {
operands[i] = match;
continue;
}
@@ -434,7 +437,7 @@ export class ShadowStackPass extends Pass {
let value = _BinaryenLocalSetGetValue(localSet);
let match = matchPattern(module, value);
if (!match) return;
if (!needsSlot(module, match)) {
if (!needsSlot(match)) {
_BinaryenLocalSetSetValue(localSet, match);
return;
}
18 changes: 18 additions & 0 deletions src/program.ts
Original file line number Diff line number Diff line change
@@ -3088,6 +3088,13 @@ export abstract class Element {
return (this.flags & vis) == (other.flags & vis);
}

visibilityNoLessThan(other: Element): bool {
if (this.isPublic) return true; // public is a most frequent case
if (this.is(CommonFlags.Private)) return other.is(CommonFlags.Private);
if (this.is(CommonFlags.Protected)) return other.isAny(CommonFlags.Private | CommonFlags.Protected);
return assert(false);
}

/** Tests if this element is bound to a class. */
get isBound(): bool {
let parent = this.parent;
@@ -4174,6 +4181,17 @@ export class Property extends VariableLikeElement {
get isField(): bool {
return this.prototype.isField;
}

checkVisibility(diag: DiagnosticEmitter): void {
let propertyGetter = this.getterInstance;
let propertySetter = this.setterInstance;
if (propertyGetter && propertySetter && !propertyGetter.visibilityNoLessThan(propertySetter)) {
diag.errorRelated(
DiagnosticCode.Get_accessor_0_must_be_at_least_as_accessible_as_the_setter,
propertyGetter.identifierNode.range, propertySetter.identifierNode.range, propertyGetter.identifierNode.text
);
}
}
}

/** A resolved index signature. */
70 changes: 25 additions & 45 deletions src/resolver.ts
Original file line number Diff line number Diff line change
@@ -1440,8 +1440,10 @@ export class Resolver extends DiagnosticEmitter {
case ElementKind.InterfacePrototype:
case ElementKind.Class:
case ElementKind.Interface: {
let classLikeTarget = target;
let findBase = false;
do {
let member = target.getMember(propertyName);
let member = classLikeTarget.getMember(propertyName);
if (member) {
if (member.kind == ElementKind.PropertyPrototype) {
let propertyInstance = this.resolveProperty(<PropertyPrototype>member, reportMode);
@@ -1458,34 +1460,32 @@ export class Resolver extends DiagnosticEmitter {
this.currentElementExpression = null;
return member; // instance FIELD, static GLOBAL, FUNCTION_PROTOTYPE, PROPERTY...
}
// traverse inherited static members on the base prototype if target is a class prototype
if (
target.kind == ElementKind.ClassPrototype ||
target.kind == ElementKind.InterfacePrototype
) {
let classPrototype = <ClassPrototype>target;
let basePrototype = classPrototype.basePrototype;
if (basePrototype) {
target = basePrototype;
} else {
findBase = false;
switch (classLikeTarget.kind) {
case ElementKind.ClassPrototype:
case ElementKind.InterfacePrototype: {
// traverse inherited static members on the base prototype if target is a class prototype
let classPrototype = <ClassPrototype>classLikeTarget;
let basePrototype = classPrototype.basePrototype;
if (basePrototype) {
findBase = true;
classLikeTarget = basePrototype;
}
break;
}
// traverse inherited instance members on the base class if target is a class instance
} else if (
target.kind == ElementKind.Class ||
target.kind == ElementKind.Interface
) {
let classInstance = <Class>target;
let baseInstance = classInstance.base;
if (baseInstance) {
target = baseInstance;
} else {
case ElementKind.Class:
case ElementKind.Interface: {
// traverse inherited instance members on the base class if target is a class instance
let classInstance = <Class>classLikeTarget;
let baseInstance = classInstance.base;
if (baseInstance) {
findBase = true;
classLikeTarget = baseInstance;
}
break;
}
} else {
break;
}
} while (true);
} while (findBase);
break;
}
default: { // enums or other namespace-like elements
@@ -3384,7 +3384,6 @@ export class Resolver extends DiagnosticEmitter {
// Resolve instance members
let prototype = instance.prototype;
let instanceMemberPrototypes = prototype.instanceMembers;
let properties = new Array<Property>();
if (instanceMemberPrototypes) {
// TODO: for (let member of instanceMemberPrototypes.values()) {
for (let _values = Map_values(instanceMemberPrototypes), i = 0, k = _values.length; i < k; ++i) {
@@ -3464,26 +3463,6 @@ export class Resolver extends DiagnosticEmitter {
}
}

// Check that property getters and setters match
for (let i = 0, k = properties.length; i < k; ++i) {
let property = properties[i];
let propertyGetter = property.getterInstance;
if (!propertyGetter) {
this.error(
DiagnosticCode.Property_0_only_has_a_setter_and_is_missing_a_getter,
property.identifierNode.range, property.name
);
} else {
let propertySetter = property.setterInstance;
if (propertySetter && !propertyGetter.visibilityEquals(propertySetter)) {
this.errorRelated(
DiagnosticCode.Getter_and_setter_accessors_do_not_agree_in_visibility,
propertyGetter.identifierNode.range, propertySetter.identifierNode.range
);
}
}
}

if (instance.kind != ElementKind.Interface) {

// Check that all required members are implemented
@@ -3707,6 +3686,7 @@ export class Resolver extends DiagnosticEmitter {
}
}
}
instance.checkVisibility(this);
return instance;
}

39 changes: 23 additions & 16 deletions tests/cli/options.js
Original file line number Diff line number Diff line change
@@ -2,18 +2,21 @@ import assert from "assert";
import * as optionsUtil from "../../util/options.js";

const config = {
"enable": {
"type": "S",
"mutuallyExclusive": "disable"
enable: {
type: "S",
mutuallyExclusive: "disable",
},
"disable": {
"type": "S",
"mutuallyExclusive": "enable"
disable: {
type: "S",
mutuallyExclusive: "enable",
},
other: {
type: "S",
default: ["x"],
},
bool_input_for_string: {
type: "s",
},
"other": {
"type": "S",
"default": ["x"]
}
};

// Present in both should concat
@@ -33,17 +36,21 @@ assert.deepStrictEqual(merged.enable, ["c"]);
assert.deepStrictEqual(merged.disable, ["a", "b"]);

// Populating defaults should work after the fact
optionsUtil.addDefaults(config, merged = {});
optionsUtil.addDefaults(config, (merged = {}));
assert.deepStrictEqual(merged.other, ["x"]);

optionsUtil.addDefaults(config, merged = { other: ["y"] });
optionsUtil.addDefaults(config, (merged = { other: ["y"] }));
assert.deepStrictEqual(merged.other, ["y"]);

// String test
assert.deepStrictEqual(merged.bool_input_for_string, undefined);
merged = optionsUtil.merge(config, {}, { bool_input_for_string: false });
assert.deepStrictEqual(merged.bool_input_for_string, undefined);
merged = optionsUtil.merge(config, {}, { bool_input_for_string: true });
assert.deepStrictEqual(merged.bool_input_for_string, "");

// Complete usage test
let result = optionsUtil.parse([
"--enable", "a",
"--disable", "b",
], config, false);
let result = optionsUtil.parse(["--enable", "a", "--disable", "b"], config, false);

merged = optionsUtil.merge(config, result.options, { enable: ["b", "c"] });
merged = optionsUtil.merge(config, merged, { disable: ["a", "d"] });
9 changes: 9 additions & 0 deletions tests/compiler/class-errors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"asc_flags": [
],
"stderr": [
"TS2304: Cannot find name 'T'.",
"TS2339: Property 'v' does not exist on type 'class-errors/A'.",
"EOF"
]
}
7 changes: 7 additions & 0 deletions tests/compiler/class-errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class A {
v: T;
}

new A().v;

ERROR("EOF");
8 changes: 8 additions & 0 deletions tests/compiler/getter-setter-errors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"asc_flags": [
],
"stderr": [
"TS2808: Get accessor 'm2' must be at least as accessible as the setter.",
"EOF"
]
}
16 changes: 16 additions & 0 deletions tests/compiler/getter-setter-errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class GetSetWithoutDifferenceVisibility {
public get m1(): i32 {
return 1;
}
private set m1(v: i32) {}

private get m2(): i32 {
return 1;
}
public set m2(v: i32) {}
}

new GetSetWithoutDifferenceVisibility().m1; // m1 is valid
new GetSetWithoutDifferenceVisibility().m2; // m2 is invalid

ERROR("EOF");
8 changes: 2 additions & 6 deletions tests/compiler/resolve-unary.debug.wat
Original file line number Diff line number Diff line change
@@ -3753,10 +3753,8 @@
call $~lib/builtins/abort
unreachable
end
global.get $~lib/memory/__stack_pointer
global.get $resolve-unary/bar
local.tee $6
i32.store
local.set $6
global.get $~lib/memory/__stack_pointer
local.get $6
i32.store offset=12
@@ -3789,10 +3787,8 @@
call $~lib/builtins/abort
unreachable
end
global.get $~lib/memory/__stack_pointer
global.get $resolve-unary/bar
local.tee $6
i32.store
local.set $6
global.get $~lib/memory/__stack_pointer
local.get $6
i32.store offset=12
8 changes: 0 additions & 8 deletions tests/compiler/resolve-unary.release.wat
Original file line number Diff line number Diff line change
@@ -2626,10 +2626,6 @@
global.get $~lib/memory/__stack_pointer
local.tee $0
global.get $resolve-unary/bar
local.tee $1
i32.store
local.get $0
local.get $1
i32.store offset=12
local.get $0
i32.const 3680
@@ -2655,10 +2651,6 @@
global.get $~lib/memory/__stack_pointer
local.tee $0
global.get $resolve-unary/bar
local.tee $1
i32.store
local.get $0
local.get $1
i32.store offset=12
local.get $0
i32.const 3712
1 change: 1 addition & 0 deletions util/options.js
Original file line number Diff line number Diff line change
@@ -150,6 +150,7 @@ function sanitizeValue(value, type) {
case "f": return Number(value) || 0;
case "s": {
if (value === true) return "";
if (value === false) return null;
return String(value);
}
case "I": {