Skip to content

BREAKING CHANGE: Unify Math & Mathf. Make every method in Math polymorphic #2335

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
12 changes: 6 additions & 6 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,7 @@ export namespace CommonNames {
export const ArrayBufferView = "ArrayBufferView";
export const ArrayBuffer = "ArrayBuffer";
export const Math = "Math";
export const Mathf = "Mathf";
export const NativeMath = "NativeMath";
export const NativeMathf = "NativeMathf";
export const Int8Array = "Int8Array";
export const Int16Array = "Int16Array";
export const Int32Array = "Int32Array";
Expand All @@ -236,10 +234,12 @@ export namespace CommonNames {
export const abort = "abort";
export const trace = "trace";
export const seed = "seed";
export const pow = "pow";
export const ipow32 = "ipow32";
export const ipow64 = "ipow64";
export const mod = "mod";
export const fpow32 = "~lib/util/math/pow32";
export const fpow64 = "~lib/util/math/pow64";
export const ipow32 = "~lib/util/math/ipow32";
export const ipow64 = "~lib/util/math/ipow64";
export const fmod32 = "~lib/util/math/mod32";
export const fmod64 = "~lib/util/math/mod64";
export const alloc = "__alloc";
export const realloc = "__realloc";
export const free = "__free";
Expand Down
60 changes: 12 additions & 48 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5327,23 +5327,14 @@ export class Compiler extends DiagnosticEmitter {
}
let instance = this.f32PowInstance;
if (!instance) {
let namespace = this.program.lookup(CommonNames.Mathf);
if (!namespace) {
this.error(
DiagnosticCode.Cannot_find_name_0,
reportNode.range, "Mathf"
);
return module.unreachable();
}
let namespaceMembers = namespace.members;
if (!namespaceMembers || !namespaceMembers.has(CommonNames.pow)) {
let prototype = this.program.lookup(CommonNames.fpow32);
if (!prototype) {
this.error(
DiagnosticCode.Cannot_find_name_0,
reportNode.range, "Mathf.pow"
reportNode.range, "pow32"
);
return module.unreachable();
}
let prototype = assert(namespaceMembers.get(CommonNames.pow));
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
this.f32PowInstance = instance = this.resolver.resolveFunction(<FunctionPrototype>prototype, null);
}
Expand All @@ -5369,23 +5360,14 @@ export class Compiler extends DiagnosticEmitter {
}
let instance = this.f64PowInstance;
if (!instance) {
let namespace = this.program.lookup(CommonNames.Math);
if (!namespace) {
this.error(
DiagnosticCode.Cannot_find_name_0,
reportNode.range, "Math"
);
return module.unreachable();
}
let namespaceMembers = namespace.members;
if (!namespaceMembers || !namespaceMembers.has(CommonNames.pow)) {
let prototype = this.program.lookup(CommonNames.fpow64);
if (!prototype) {
this.error(
DiagnosticCode.Cannot_find_name_0,
reportNode.range, "Math.pow"
reportNode.range, "pow64"
);
return module.unreachable();
}
let prototype = assert(namespaceMembers.get(CommonNames.pow));
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
this.f64PowInstance = instance = this.resolver.resolveFunction(<FunctionPrototype>prototype, null);
}
Expand Down Expand Up @@ -5507,23 +5489,14 @@ export class Compiler extends DiagnosticEmitter {
case TypeKind.F32: {
let instance = this.f32ModInstance;
if (!instance) {
let namespace = this.program.lookup(CommonNames.Mathf);
if (!namespace) {
this.error(
DiagnosticCode.Cannot_find_name_0,
reportNode.range, "Mathf"
);
return module.unreachable();
}
let namespaceMembers = namespace.members;
if (!namespaceMembers || !namespaceMembers.has(CommonNames.mod)) {
let prototype = this.program.lookup(CommonNames.fmod32);
if (!prototype) {
this.error(
DiagnosticCode.Cannot_find_name_0,
reportNode.range, "Mathf.mod"
reportNode.range, "mod32"
);
return module.unreachable();
}
let prototype = assert(namespaceMembers.get(CommonNames.mod));
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
this.f32ModInstance = instance = this.resolver.resolveFunction(<FunctionPrototype>prototype, null);
}
Expand All @@ -5535,23 +5508,14 @@ export class Compiler extends DiagnosticEmitter {
case TypeKind.F64: {
let instance = this.f64ModInstance;
if (!instance) {
let namespace = this.program.lookup(CommonNames.Math);
if (!namespace) {
this.error(
DiagnosticCode.Cannot_find_name_0,
reportNode.range, "Math"
);
return module.unreachable();
}
let namespaceMembers = namespace.members;
if (!namespaceMembers || !namespaceMembers.has(CommonNames.mod)) {
let prototype = this.program.lookup(CommonNames.fmod64);
if (!prototype) {
this.error(
DiagnosticCode.Cannot_find_name_0,
reportNode.range, "Math.mod"
reportNode.range, "mod64"
);
return module.unreachable();
}
let prototype = assert(namespaceMembers.get(CommonNames.mod));
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
this.f64ModInstance = instance = this.resolver.resolveFunction(<FunctionPrototype>prototype, null);
}
Expand Down
3 changes: 0 additions & 3 deletions src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1401,9 +1401,6 @@ export class Program extends DiagnosticEmitter {
if (!globalAliases.has(CommonNames.Math)) {
globalAliases.set(CommonNames.Math, CommonNames.NativeMath);
}
if (!globalAliases.has(CommonNames.Mathf)) {
globalAliases.set(CommonNames.Mathf, CommonNames.NativeMathf);
}
// TODO: for (let [alias, name] of globalAliases) {
for (let _keys = Map_keys(globalAliases), i = 0, k = _keys.length; i < k; ++i) {
let alias = unchecked(_keys[i]);
Expand Down
142 changes: 70 additions & 72 deletions std/assembly/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2024,128 +2024,122 @@ interface SymbolConstructor {

declare const Symbol: SymbolConstructor;

// prevent infer T as literal
/** @internal */
interface IMath<T> {
type Widen<T> = T extends number ? number : T;

/** @internal */
interface IMath {
/** The base of natural logarithms, e, approximately 2.718. */
readonly E: T;
readonly E: f64;
/** The natural logarithm of 2, approximately 0.693. */
readonly LN2: T;
readonly LN2: f64;
/** The natural logarithm of 10, approximately 2.302. */
readonly LN10: T;
readonly LN10: f64;
/** The base 2 logarithm of e, approximately 1.442. */
readonly LOG2E: T;
readonly LOG2E: f64;
/** The base 10 logarithm of e, approximately 0.434. */
readonly LOG10E: T;
readonly LOG10E: f64;
/** The ratio of the circumference of a circle to its diameter, approximately 3.14159. */
readonly PI: T;
readonly PI: f64;
/** The square root of 1/2, approximately 0.707. */
readonly SQRT1_2: T;
readonly SQRT1_2: f64;
/** The square root of 2, approximately 1.414. */
readonly SQRT2: T;
readonly SQRT2: f64;
/** Returns the absolute value of `x`. */
abs(x: T): T;
abs<T extends Widen<u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>>(x: T): Widen<T>;
/** Returns the arccosine (in radians) of `x`. */
acos(x: T): T;
acos<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the hyperbolic arc-cosine of `x`. */
acosh(x: T): T;
acosh<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the arcsine (in radians) of `x`. */
asin(x: T): T;
asin<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the hyperbolic arcsine of `x`. */
asinh(x: T): T;
asinh<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the arctangent (in radians) of `x`. */
atan(x: T): T;
atan<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the arctangent of the quotient of its arguments. */
atan2(y: T, x: T): T;
atan2<T extends f32 | f64>(y: T, x: T): Widen<T>;
/** Returns the hyperbolic arctangent of `x`. */
atanh(x: T): T;
atanh<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the cube root of `x`. */
cbrt(x: T): T;
cbrt<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the smallest integer greater than or equal to `x`. */
ceil(x: T): T;
/** Returns the number of leading zero bits in the 32-bit binary representation of `x`. */
clz32(x: T): T;
ceil<T extends u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>(x: T): Widen<T>;
/** @deprecated Returns the number of leading zero bits in the 32-bit binary representation of `x`. */
clz32<T extends u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>(x: T): Widen<T>;
/** Returns the cosine (in radians) of `x`. */
cos(x: T): T;
cos<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the hyperbolic cosine of `x`. */
cosh(x: T): T;
cosh<T extends f32 | f64>(x: T): Widen<T>;
/** Returns e to the power of `x`. */
exp(x: T): T;
exp<T extends f32 | f64>(x: T): Widen<T>;
/** Returns e to the power of `x`, minus 1. */
expm1(x: T): T;
expm1<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the largest integer less than or equal to `x`. */
floor(x: T): T;
/** Returns the nearest 32-bit single precision float representation of `x`. */
fround(x: T): T;
floor<T extends u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>(x: T): Widen<T>;
/** @deprecated Returns the nearest 32-bit single precision float representation of `x`. */
fround<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the square root of the sum of squares of its arguments. */
hypot(value1: T, value2: T): T; // TODO: rest
/** Returns the result of the C-like 32-bit multiplication of `a` and `b`. */
imul(a: T, b: T): T;
hypot<T extends f32 | f64>(a: T, b: T): Widen<T>; // TODO: rest
/** @deprecated Returns the result of the C-like 32-bit multiplication of `a` and `b`. */
imul<T extends u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>(a: T, b: T): Widen<T>;
/** Returns the natural logarithm (base e) of `x`. */
log(x: T): T;
log<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the base 10 logarithm of `x`. */
log10(x: T): T;
log10<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the natural logarithm (base e) of 1 + `x`. */
log1p(x: T): T;
log1p<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the base 2 logarithm of `x`. */
log2(x: T): T;
log2<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the largest-valued number of its arguments. */
max(value1: T, value2: T): T; // TODO: rest
max<T extends u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>(a: T, b: T): Widen<T>; // TODO: rest
/** Returns the lowest-valued number of its arguments. */
min(value1: T, value2: T): T; // TODO: rest
min<T extends u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>(a: T, b: T): Widen<T>; // TODO: rest
/** Returns `base` to the power of `exponent`. */
pow(base: T, exponent: T): T;
pow<T extends f32 | f64>(base: T, exponent: T): Widen<T>;
/** Returns a pseudo-random number in the range from 0.0 inclusive up to but not including 1.0. */
random(): T;
random(): f64;
/** Returns the value of `x` rounded to the nearest integer. */
round(x: T): T;
round<T extends u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>(x: T): Widen<T>;
/** Returns the sign of `x`, indicating whether the number is positive, negative or zero. */
sign(x: T): T;
sign<T extends u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>(x: T): Widen<T>;
/** Returns whether the sign bit of `x` is set. */
signbit(x: T): bool;
signbit<T extends u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>(x: T): bool;
/** Returns the sine of `x`. */
sin(x: T): T;
sin<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the hyperbolic sine of `x`. */
sinh(x: T): T;
sinh<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the square root of `x`. */
sqrt(x: T): T;
sqrt<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the tangent of `x`. */
tan(x: T): T;
tan<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the hyperbolic tangent of `x`. */
tanh(x: T): T;
tanh<T extends f32 | f64>(x: T): Widen<T>;
/** Returns the integer part of `x` by removing any fractional digits. */
trunc(x: T): T;
trunc<T extends u8 | u16 | u32 | u64 | i8 | i16 | i32 | i64 | f32 | f64>(x: T): Widen<T>;
}

/** @internal */
interface INativeMath<T> extends IMath<T> {
/** Contains sin value produced after Math/Mathf.sincos */
sincos_sin: T;
/** Contains cos value produced after Math/Mathf.sincos */
sincos_cos: T;
interface INativeMath extends IMath {
/** Contains sin value produced after Math.sincos */
sincos_sin: f64;
/** Contains cos value produced after Math.sincos */
sincos_cos: f64;
/** Seeds the random number generator. */
seedRandom(value: i64): void;
/** Multiplies a floating point `x` by 2 raised to power exp `n`. */
scalbn(x: T, n: i32): T;
/** Returns the floating-point remainder of `x / y` (rounded towards zero). */
mod(x: T, y: T): T;
/** Returns the floating-point remainder of `x / y` (rounded to nearest). */
rem(x: T, y: T): T;
/** Returns sin and cos simultaneously for same angle. Results stored to `sincos_s32/64` and `sincos_c32/64` globals */
sincos(x: T): void;
sincos<T extends f32 | f64>(x: T): void;
/** Returns 2 raised to the given power x. Equivalent to 2 ** x. */
exp2(x: T): T;
exp2<T extends f32 | f64>(x: T): Widen<T>;
}

/** Double precision math imported from JavaScript. */
declare const JSMath: IMath<f64>;
declare const JSMath: IMath;
/** Double precision math implemented natively. */
declare const NativeMath: INativeMath<f64>;
/** Single precision math implemented natively. */
declare const NativeMathf: INativeMath<f32>;
declare const NativeMath: INativeMath;
/** Alias of {@link NativeMath} or {@link JSMath} respectively. Defaults to `NativeMath`. */
declare const Math: IMath<f64>;
/** Alias of {@link NativeMathf} or {@link JSMath} respectively. Defaults to `NativeMathf`. */
declare const Mathf: IMath<f32>;
declare const Math: IMath;

/** Environmental abort function. */
declare function abort(msg?: string | null, fileName?: string | null, lineNumber?: i32, columnNumber?: i32): never;
Expand Down Expand Up @@ -2234,8 +2228,10 @@ interface TypedPropertyDescriptor<T> {

/** Annotates a method as a binary operator overload for the specified `token`. */
declare function operator(token:
"[]" | "[]=" | "{}" | "{}=" | "==" | "!=" | ">" | "<" | "<=" | ">=" |
">>" | ">>>" | "<<" | "&" | "|" | "^" | "+" | "-" | "*" | "**" | "/" | "%"
| "[]" | "[]=" | "{}" | "{}="
| "==" | "!=" | ">" | "<" | "<=" | ">="
| ">>" | ">>>" | "<<" | "&" | "|" | "^"
| "+" | "-" | "*" | "**" | "/" | "%"
): (
target: any,
propertyKey: string,
Expand All @@ -2245,8 +2241,10 @@ declare function operator(token:
declare namespace operator {
/** Annotates a method as a binary operator overload for the specified `token`. */
export function binary(token:
"[]" | "[]=" | "{}" | "{}=" | "==" | "!=" | ">" | "<" | "<=" | ">=" |
">>" | ">>>" | "<<" | "&" | "|" | "^" | "+" | "-" | "*" | "**" | "/" | "%"
| "[]" | "[]=" | "{}" | "{}="
| "==" | "!=" | ">" | "<" | "<=" | ">="
| ">>" | ">>>" | "<<" | "&" | "|" | "^"
| "+" | "-" | "*" | "**" | "/" | "%"
): (
target: any,
propertyKey: string,
Expand Down
Loading