Skip to content

Commit fd23df7

Browse files
authored
Represent indexed access with a typed element (AssemblyScript#845)
1 parent 605e054 commit fd23df7

File tree

7 files changed

+5773
-133
lines changed

7 files changed

+5773
-133
lines changed

src/compiler.ts

Lines changed: 72 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ import {
7878
OperatorKind,
7979
DecoratorFlags,
8080
PropertyPrototype,
81+
IndexSignature,
8182
File,
8283
mangleInternalName
8384
} from "./program";
@@ -578,7 +579,8 @@ export class Compiler extends DiagnosticEmitter {
578579
case ElementKind.ENUM:
579580
case ElementKind.NAMESPACE:
580581
case ElementKind.FILE:
581-
case ElementKind.TYPEDEFINITION: break;
582+
case ElementKind.TYPEDEFINITION:
583+
case ElementKind.INDEXSIGNATURE: break;
582584

583585
default: assert(false); // unexpected module export
584586
}
@@ -697,7 +699,8 @@ export class Compiler extends DiagnosticEmitter {
697699
}
698700
case ElementKind.NAMESPACE:
699701
case ElementKind.TYPEDEFINITION:
700-
case ElementKind.ENUMVALUE: break;
702+
case ElementKind.ENUMVALUE:
703+
case ElementKind.INDEXSIGNATURE: break;
701704
default: assert(false, ElementKind[element.kind]);
702705
}
703706
if (compileMembers) this.compileMembers(element);
@@ -5220,44 +5223,30 @@ export class Compiler extends DiagnosticEmitter {
52205223
if (setterInstance.hasDecorator(DecoratorFlags.UNSAFE)) this.checkUnsafe(expression);
52215224
break;
52225225
}
5223-
case ElementKind.CLASS: {
5224-
if (elementExpression) { // indexed access
5225-
let isUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT);
5226-
// if (isUnchecked) {
5227-
// let arrayType = this.program.determineBuiltinArrayType(<Class>target);
5228-
// if (arrayType) {
5229-
// return compileBuiltinArraySet(
5230-
// this,
5231-
// <Class>target,
5232-
// assert(this.resolver.currentThisExpression),
5233-
// elementExpression,
5234-
// valueExpression,
5235-
// contextualType
5236-
// );
5237-
// }
5238-
// }
5239-
let indexedSet = (<Class>target).lookupOverload(OperatorKind.INDEXED_SET, isUnchecked);
5240-
if (!indexedSet) {
5241-
let indexedGet = (<Class>target).lookupOverload(OperatorKind.INDEXED_GET, isUnchecked);
5242-
if (!indexedGet) {
5243-
this.error(
5244-
DiagnosticCode.Index_signature_is_missing_in_type_0,
5245-
expression.range, (<Class>target).internalName
5246-
);
5247-
} else {
5248-
this.error(
5249-
DiagnosticCode.Index_signature_in_type_0_only_permits_reading,
5250-
expression.range, (<Class>target).internalName
5251-
);
5252-
}
5253-
return this.module.unreachable();
5226+
case ElementKind.INDEXSIGNATURE: {
5227+
let parent = (<IndexSignature>target).parent;
5228+
assert(parent.kind == ElementKind.CLASS);
5229+
let isUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT);
5230+
let indexedSet = (<Class>parent).lookupOverload(OperatorKind.INDEXED_SET, isUnchecked);
5231+
if (!indexedSet) {
5232+
let indexedGet = (<Class>parent).lookupOverload(OperatorKind.INDEXED_GET, isUnchecked);
5233+
if (!indexedGet) {
5234+
this.error(
5235+
DiagnosticCode.Index_signature_is_missing_in_type_0,
5236+
expression.range, (<Class>parent).internalName
5237+
);
5238+
} else {
5239+
this.error(
5240+
DiagnosticCode.Index_signature_in_type_0_only_permits_reading,
5241+
expression.range, (<Class>parent).internalName
5242+
);
52545243
}
5255-
assert(indexedSet.signature.parameterTypes.length == 2); // parser must guarantee this
5256-
targetType = indexedSet.signature.parameterTypes[1]; // 2nd parameter is the element
5257-
if (indexedSet.hasDecorator(DecoratorFlags.UNSAFE)) this.checkUnsafe(expression);
5258-
break;
5244+
return this.module.unreachable();
52595245
}
5260-
// fall-through
5246+
assert(indexedSet.signature.parameterTypes.length == 2); // parser must guarantee this
5247+
targetType = indexedSet.signature.parameterTypes[1]; // 2nd parameter is the element
5248+
if (indexedSet.hasDecorator(DecoratorFlags.UNSAFE)) this.checkUnsafe(expression);
5249+
break;
52615250
}
52625251
default: {
52635252
this.error(
@@ -5405,55 +5394,54 @@ export class Compiler extends DiagnosticEmitter {
54055394
], valueExpression)
54065395
], nativeReturnType);
54075396
}
5408-
case ElementKind.CLASS: {
5397+
case ElementKind.INDEXSIGNATURE: {
54095398
if (this.skippedAutoreleases.has(valueExpr)) valueExpr = this.makeAutorelease(valueExpr, flow); // (*)
5410-
if (indexExpression) {
5411-
let isUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT);
5412-
let indexedGet = (<Class>target).lookupOverload(OperatorKind.INDEXED_GET, isUnchecked);
5413-
if (!indexedGet) {
5414-
this.error(
5415-
DiagnosticCode.Index_signature_is_missing_in_type_0,
5416-
valueExpression.range, target.internalName
5417-
);
5418-
return module.unreachable();
5419-
}
5420-
let indexedSet = (<Class>target).lookupOverload(OperatorKind.INDEXED_SET, isUnchecked);
5421-
if (!indexedSet) {
5422-
this.error(
5423-
DiagnosticCode.Index_signature_in_type_0_only_permits_reading,
5424-
valueExpression.range, target.internalName
5425-
);
5426-
this.currentType = tee ? indexedGet.signature.returnType : Type.void;
5427-
return module.unreachable();
5428-
}
5429-
let targetType = (<Class>target).type;
5430-
let thisExpr = this.compileExpression(assert(thisExpression), this.options.usizeType);
5431-
let elementExpr = this.compileExpression(indexExpression, Type.i32, Constraints.CONV_IMPLICIT);
5432-
if (tee) {
5433-
let tempLocalTarget = flow.getTempLocal(targetType);
5434-
let tempLocalElement = flow.getAndFreeTempLocal(this.currentType);
5435-
let returnType = indexedGet.signature.returnType;
5436-
flow.freeTempLocal(tempLocalTarget);
5437-
return module.block(null, [
5438-
this.makeCallDirect(indexedSet, [
5439-
module.local_tee(tempLocalTarget.index, thisExpr),
5440-
module.local_tee(tempLocalElement.index, elementExpr),
5441-
valueExpr
5442-
], valueExpression),
5443-
this.makeCallDirect(indexedGet, [
5444-
module.local_get(tempLocalTarget.index, tempLocalTarget.type.toNativeType()),
5445-
module.local_get(tempLocalElement.index, tempLocalElement.type.toNativeType())
5446-
], valueExpression)
5447-
], returnType.toNativeType());
5448-
} else {
5449-
return this.makeCallDirect(indexedSet, [
5450-
thisExpr,
5451-
elementExpr,
5399+
let isUnchecked = flow.is(FlowFlags.UNCHECKED_CONTEXT);
5400+
let parent = (<IndexSignature>target).parent;
5401+
assert(parent.kind == ElementKind.CLASS);
5402+
let indexedGet = (<Class>parent).lookupOverload(OperatorKind.INDEXED_GET, isUnchecked);
5403+
if (!indexedGet) {
5404+
this.error(
5405+
DiagnosticCode.Index_signature_is_missing_in_type_0,
5406+
valueExpression.range, parent.internalName
5407+
);
5408+
return module.unreachable();
5409+
}
5410+
let indexedSet = (<Class>parent).lookupOverload(OperatorKind.INDEXED_SET, isUnchecked);
5411+
if (!indexedSet) {
5412+
this.error(
5413+
DiagnosticCode.Index_signature_in_type_0_only_permits_reading,
5414+
valueExpression.range, parent.internalName
5415+
);
5416+
this.currentType = tee ? indexedGet.signature.returnType : Type.void;
5417+
return module.unreachable();
5418+
}
5419+
let targetType = (<Class>parent).type;
5420+
let thisExpr = this.compileExpression(assert(thisExpression), this.options.usizeType);
5421+
let elementExpr = this.compileExpression(assert(indexExpression), Type.i32, Constraints.CONV_IMPLICIT);
5422+
if (tee) {
5423+
let tempLocalTarget = flow.getTempLocal(targetType);
5424+
let tempLocalElement = flow.getAndFreeTempLocal(this.currentType);
5425+
let returnType = indexedGet.signature.returnType;
5426+
flow.freeTempLocal(tempLocalTarget);
5427+
return module.block(null, [
5428+
this.makeCallDirect(indexedSet, [
5429+
module.local_tee(tempLocalTarget.index, thisExpr),
5430+
module.local_tee(tempLocalElement.index, elementExpr),
54525431
valueExpr
5453-
], valueExpression);
5454-
}
5432+
], valueExpression),
5433+
this.makeCallDirect(indexedGet, [
5434+
module.local_get(tempLocalTarget.index, tempLocalTarget.type.toNativeType()),
5435+
module.local_get(tempLocalElement.index, tempLocalElement.type.toNativeType())
5436+
], valueExpression)
5437+
], returnType.toNativeType());
5438+
} else {
5439+
return this.makeCallDirect(indexedSet, [
5440+
thisExpr,
5441+
elementExpr,
5442+
valueExpr
5443+
], valueExpression);
54555444
}
5456-
// fall-through
54575445
}
54585446
}
54595447
this.error(

src/program.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1200,7 +1200,7 @@ export class Program extends DiagnosticEmitter {
12001200
} else if (flags & flag) {
12011201
this.error(
12021202
DiagnosticCode.Duplicate_decorator,
1203-
decorator.range, decorator.name.range.toString()
1203+
decorator.range
12041204
);
12051205
} else {
12061206
flags |= flag;
@@ -1985,6 +1985,8 @@ export enum ElementKind {
19851985
FILE,
19861986
/** A {@link TypeDefinition}. */
19871987
TYPEDEFINITION,
1988+
/** An {@link IndexSignature}. */
1989+
INDEXSIGNATURE
19881990
}
19891991

19901992
/** Indicates built-in decorators that are present. */
@@ -3081,6 +3083,33 @@ export class Property extends VariableLikeElement {
30813083
}
30823084
}
30833085

3086+
/** An resolved index signature. */
3087+
export class IndexSignature extends VariableLikeElement {
3088+
3089+
/** Constructs a new index prototype. */
3090+
constructor(
3091+
/** Parent class. */
3092+
parent: Class
3093+
) {
3094+
super(ElementKind.INDEXSIGNATURE, parent.internalName + "[]", parent);
3095+
}
3096+
3097+
/** Obtains the getter instance. */
3098+
getGetterInstance(isUnchecked: bool): Function | null {
3099+
return (<Class>this.parent).lookupOverload(OperatorKind.INDEXED_GET, isUnchecked);
3100+
}
3101+
3102+
/** Obtains the setter instance. */
3103+
getSetterInstance(isUnchecked: bool): Function | null {
3104+
return (<Class>this.parent).lookupOverload(OperatorKind.INDEXED_SET, isUnchecked);
3105+
}
3106+
3107+
/* @override */
3108+
lookup(name: string): Element | null {
3109+
return this.parent.lookup(name);
3110+
}
3111+
}
3112+
30843113
/** A yet unresolved class prototype. */
30853114
export class ClassPrototype extends DeclaredElement {
30863115

@@ -3213,6 +3242,8 @@ export class Class extends TypedElement {
32133242
constructorInstance: Function | null = null;
32143243
/** Operator overloads. */
32153244
overloads: Map<OperatorKind,Function> | null = null;
3245+
/** Index signature, if present. */
3246+
indexSignature: IndexSignature | null = null;
32163247
/** Unique class id. */
32173248
private _id: u32 = 0;
32183249
/** Remembers acyclic state. */

0 commit comments

Comments
 (0)