diff --git a/src/compiler.ts b/src/compiler.ts index 9d2c3ca6f7..192f0dc8a1 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -195,7 +195,7 @@ import { writeF32, writeF64, writeV128, - uniqueMap, + cloneMap, isPowerOf2, v128_zero, readI32, @@ -2848,7 +2848,7 @@ export class Compiler extends DiagnosticEmitter { type = resolver.resolveType( // reports typeNode, flow.actualFunction, - uniqueMap(flow.contextualTypeArguments) + cloneMap(flow.contextualTypeArguments) ); if (!type) continue; this.checkTypeSupported(type, typeNode); @@ -3626,7 +3626,7 @@ export class Compiler extends DiagnosticEmitter { let toType = this.resolver.resolveType( // reports assert(expression.toType), flow.actualFunction, - uniqueMap(flow.contextualTypeArguments) + cloneMap(flow.contextualTypeArguments) ); if (!toType) return this.module.unreachable(); return this.compileExpression(expression.expression, toType, inheritedConstraints | Constraints.CONV_EXPLICIT); @@ -6419,7 +6419,7 @@ export class Compiler extends DiagnosticEmitter { assert(typeParameterNodes), typeArgumentNodes, this.currentFlow.actualFunction.parent, - uniqueMap(this.currentFlow.contextualTypeArguments), // don't update + cloneMap(this.currentFlow.contextualTypeArguments), // don't update expression ); } @@ -7333,7 +7333,7 @@ export class Compiler extends DiagnosticEmitter { DecoratorFlags.NONE ); var instance: Function | null; - var contextualTypeArguments = uniqueMap(flow.contextualTypeArguments); + var contextualTypeArguments = cloneMap(flow.contextualTypeArguments); var module = this.module; // compile according to context. this differs from a normal function in that omitted parameter @@ -7715,7 +7715,7 @@ export class Compiler extends DiagnosticEmitter { let functionInstance = this.resolver.resolveFunction( functionPrototype, null, - uniqueMap(flow.contextualTypeArguments) + cloneMap(flow.contextualTypeArguments) ); if (!functionInstance || !this.compileFunction(functionInstance)) return module.unreachable(); if (functionInstance.hasDecorator(DecoratorFlags.BUILTIN)) { @@ -7770,7 +7770,7 @@ export class Compiler extends DiagnosticEmitter { var expectedType = this.resolver.resolveType( expression.isType, flow.actualFunction, - uniqueMap(flow.contextualTypeArguments) + cloneMap(flow.contextualTypeArguments) ); if (!expectedType) { this.currentType = Type.bool; @@ -8148,7 +8148,7 @@ export class Compiler extends DiagnosticEmitter { let instance = this.resolver.resolveFunction( target, null, - uniqueMap(), + new Map(), ReportMode.SWALLOW ); if (!instance) break; @@ -8734,14 +8734,14 @@ export class Compiler extends DiagnosticEmitter { classInstance = this.resolver.resolveClass( classPrototype, classReference.typeArguments, - uniqueMap(flow.contextualTypeArguments) + cloneMap(flow.contextualTypeArguments) ); } else { classInstance = this.resolver.resolveClassInclTypeArguments( classPrototype, typeArguments, flow.actualFunction.parent, // relative to caller - uniqueMap(flow.contextualTypeArguments), + cloneMap(flow.contextualTypeArguments), expression ); } @@ -8773,7 +8773,7 @@ export class Compiler extends DiagnosticEmitter { // clone base constructor if a derived class. note that we cannot just // call the base ctor since the derived class may have additional fields. let baseClass = classInstance.base; - let contextualTypeArguments = uniqueMap(classInstance.contextualTypeArguments); + let contextualTypeArguments = cloneMap(classInstance.contextualTypeArguments); if (baseClass) { let baseCtor = this.ensureConstructor(baseClass, reportNode); this.checkFieldInitialization(baseClass, reportNode); diff --git a/src/flow.ts b/src/flow.ts index 2ab9e4b4dc..6214f026c4 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -85,7 +85,7 @@ import { import { BitSet, - uniqueMap + cloneMap } from "./util"; import { @@ -314,7 +314,7 @@ export class Flow { branch.localFlags = this.localFlags.slice(); if (this.actualFunction.is(CommonFlags.CONSTRUCTOR)) { let thisFieldFlags = assert(this.thisFieldFlags); - branch.thisFieldFlags = uniqueMap(thisFieldFlags); + branch.thisFieldFlags = cloneMap(thisFieldFlags); } else { assert(!this.thisFieldFlags); } diff --git a/src/resolver.ts b/src/resolver.ts index 7c7aac2fa9..46d5d16570 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -95,7 +95,7 @@ import { } from "./common"; import { - uniqueMap, + cloneMap, isPowerOf2 } from "./util"; @@ -255,7 +255,7 @@ export class Resolver extends DiagnosticEmitter { element, typeArgumentNodes, ctxElement, - uniqueMap(ctxTypes), // don't inherit + cloneMap(ctxTypes), // don't inherit node, reportMode ); @@ -309,7 +309,7 @@ export class Resolver extends DiagnosticEmitter { typeParameterNodes, typeArgumentNodes, ctxElement, - ctxTypes = uniqueMap(ctxTypes), // update + ctxTypes = cloneMap(ctxTypes), // update node, reportMode ); @@ -626,7 +626,7 @@ export class Resolver extends DiagnosticEmitter { /** Contextual element. */ ctxElement: Element, /** Contextual types, i.e. `T`. Updated in place with the new set of contextual types. */ - ctxTypes: Map = uniqueMap(), + ctxTypes: Map = new Map(), /** Alternative report node in case of empty type arguments. */ alternativeReportNode: Node | null = null, /** How to proceed with eventual diagnostics. */ @@ -656,7 +656,7 @@ export class Resolver extends DiagnosticEmitter { return null; } var typeArguments = new Array(maxParameterCount); - var oldCtxTypes = uniqueMap(ctxTypes); + var oldCtxTypes = cloneMap(ctxTypes); ctxTypes.clear(); for (let i = 0; i < maxParameterCount; ++i) { let type = i < argumentCount @@ -669,7 +669,7 @@ export class Resolver extends DiagnosticEmitter { : this.resolveType( // reports assert(typeParameters[i].defaultType), ctxElement, - uniqueMap(ctxTypes), // don't update + cloneMap(ctxTypes), // don't update reportMode ); if (!type) return null; @@ -704,7 +704,7 @@ export class Resolver extends DiagnosticEmitter { prototype, typeArguments, ctxFlow.actualFunction, - uniqueMap(ctxFlow.contextualTypeArguments), // don't inherit + cloneMap(ctxFlow.contextualTypeArguments), // don't inherit node, reportMode ); @@ -712,7 +712,7 @@ export class Resolver extends DiagnosticEmitter { // infer generic call if type arguments have been omitted if (prototype.is(CommonFlags.GENERIC)) { - let contextualTypeArguments = uniqueMap(ctxFlow.contextualTypeArguments); + let contextualTypeArguments = cloneMap(ctxFlow.contextualTypeArguments); // fill up contextual types with auto for each generic component let typeParameterNodes = assert(prototype.typeParameterNodes); @@ -780,13 +780,13 @@ export class Resolver extends DiagnosticEmitter { return this.resolveFunction( prototype, resolvedTypeArguments, - uniqueMap(ctxFlow.contextualTypeArguments), + cloneMap(ctxFlow.contextualTypeArguments), reportMode ); } // otherwise resolve the non-generic call as usual - return this.resolveFunction(prototype, null, uniqueMap(), reportMode); + return this.resolveFunction(prototype, null, new Map(), reportMode); } /** Updates contextual types with a possibly encapsulated inferred type. */ @@ -1220,7 +1220,7 @@ export class Resolver extends DiagnosticEmitter { var element = this.lookupIdentifierExpression(node, ctxFlow, ctxElement, reportMode); if (!element) return null; if (element.kind == ElementKind.FUNCTION_PROTOTYPE) { - let instance = this.resolveFunction(element, null, uniqueMap(), reportMode); + let instance = this.resolveFunction(element, null, new Map(), reportMode); if (!instance) return null; element = instance; } @@ -1357,7 +1357,7 @@ export class Resolver extends DiagnosticEmitter { // Inherit from 'Function' if not overridden, i.e. fn.call let ownMember = target.getMember(propertyName); if (!ownMember) { - let functionInstance = this.resolveFunction(target, null, uniqueMap(), ReportMode.SWALLOW); + let functionInstance = this.resolveFunction(target, null, new Map(), ReportMode.SWALLOW); if (functionInstance) { let wrapper = functionInstance.type.getClassOrWrapper(this.program); if (wrapper) target = wrapper; @@ -2538,7 +2538,7 @@ export class Resolver extends DiagnosticEmitter { element, node.typeArguments, ctxFlow.actualFunction, - uniqueMap(ctxFlow.contextualTypeArguments), + cloneMap(ctxFlow.contextualTypeArguments), node, reportMode ); @@ -2625,7 +2625,7 @@ export class Resolver extends DiagnosticEmitter { /** Type arguments provided. */ typeArguments: Type[] | null, /** Contextual types, i.e. `T`. */ - ctxTypes: Map = uniqueMap(), + ctxTypes: Map = new Map(), /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Function | null { @@ -2927,7 +2927,7 @@ export class Resolver extends DiagnosticEmitter { /** Type arguments provided. */ typeArguments: Type[] | null, /** Contextual types, i.e. `T`. */ - ctxTypes: Map = uniqueMap(), + ctxTypes: Map = new Map(), /** How to proceed with eventual diagnostics. */ reportMode: ReportMode = ReportMode.REPORT ): Class | null { @@ -2988,7 +2988,7 @@ export class Resolver extends DiagnosticEmitter { basePrototype, extendsNode.typeArguments, prototype.parent, // relative to derived class - uniqueMap(ctxTypes), // don't inherit + cloneMap(ctxTypes), // don't inherit extendsNode, reportMode ); @@ -3024,7 +3024,7 @@ export class Resolver extends DiagnosticEmitter { interfacePrototype, implementsNode.typeArguments, prototype.parent, - uniqueMap(ctxTypes), + cloneMap(ctxTypes), implementsNode, reportMode ); @@ -3346,14 +3346,14 @@ export class Resolver extends DiagnosticEmitter { operatorInstance = this.resolveFunction( boundPrototype, null, - uniqueMap(), + new Map(), reportMode ); } else { operatorInstance = this.resolveFunction( overloadPrototype, null, - uniqueMap(), + new Map(), reportMode ); } @@ -3491,7 +3491,7 @@ export class Resolver extends DiagnosticEmitter { let getterInstance = this.resolveFunction( getterPrototype, null, - uniqueMap(), + new Map(), reportMode ); if (getterInstance) { @@ -3504,7 +3504,7 @@ export class Resolver extends DiagnosticEmitter { let setterInstance = this.resolveFunction( setterPrototype, null, - uniqueMap(), + new Map(), reportMode ); if (setterInstance) { diff --git a/src/util/collections.ts b/src/util/collections.ts index 134ea073b0..1a296b1292 100644 --- a/src/util/collections.ts +++ b/src/util/collections.ts @@ -3,26 +3,47 @@ * @license Apache-2.0 */ -/** Makes a unique map. Typically used to track contextual type arguemnts. */ -export function uniqueMap(original: Map | null = null, overrides: Map | null = null): Map { - var cloned = new Map(); - if (original) { - // TODO: for (let [k, v] of original) { - for (let _keys = Map_keys(original), i = 0, k = _keys.length; i < k; ++i) { - let k = unchecked(_keys[i]); - let v = assert(original.get(k)); - cloned.set(k, v); +/** Clone map. Typically used to track contextual type arguments. */ +export function cloneMap(map: Map | null): Map { + if (!ASC_TARGET) { // JS + // fast path for js target + return new Map(map); + } else { + let out = new Map(); + if (map) { + // TODO: for (let [k, v] of map) { + for (let _keys = Map_keys(map), i = 0, k = _keys.length; i < k; ++i) { + let k = unchecked(_keys[i]); + let v = assert(map.get(k)); + out.set(k, v); + } } + return out; } - if (overrides) { - // TODO: for (let [k, v] of overrides) { - for (let _keys = Map_keys(overrides), i = 0, k = _keys.length; i < k; ++i) { +} + +/** Merge two maps in into new one. */ +export function mergeMaps(map1: Map, map2: Map): Map { + if (!ASC_TARGET) { // JS + let out = new Map(map1); + map2.forEach((v, k) => out.set(k, v)); + return out; + } else { + let out = new Map(); + // TODO: for (let [k, v] of map1) { + for (let _keys = Map_keys(map1), i = 0, k = _keys.length; i < k; ++i) { + let k = unchecked(_keys[i]); + let v = assert(map1.get(k)); + out.set(k, v); + } + // TODO: for (let [k, v] of map2) { + for (let _keys = Map_keys(map2), i = 0, k = _keys.length; i < k; ++i) { let k = unchecked(_keys[i]); - let v = assert(overrides.get(k)); - cloned.set(k, v); + let v = assert(map2.get(k)); + out.set(k, v); } + return out; } - return cloned; } /** BitSet represent growable sequence of N bits. It's faster alternative of Set when elements