Skip to content

Commit 42883cb

Browse files
author
Willem Wyndham
authored
feat: Add nonnull/NonNullable builtin type (#1875)
1 parent ee5016c commit 42883cb

File tree

167 files changed

+902
-214
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

167 files changed

+902
-214
lines changed

src/common.ts

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ export namespace CommonNames {
147147
export const indexof = "indexof";
148148
export const valueof = "valueof";
149149
export const returnof = "returnof";
150+
export const nonnull = "nonnull";
150151
// aliases
151152
export const null_ = "null";
152153
export const true_ = "true";

src/program.ts

+6
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,12 @@ export class Program extends DiagnosticEmitter {
992992
this.makeNativeTypeDeclaration(CommonNames.returnof, CommonFlags.EXPORT | CommonFlags.GENERIC),
993993
DecoratorFlags.BUILTIN
994994
));
995+
this.nativeFile.add(CommonNames.nonnull, new TypeDefinition(
996+
CommonNames.nonnull,
997+
this.nativeFile,
998+
this.makeNativeTypeDeclaration(CommonNames.nonnull, CommonFlags.EXPORT | CommonFlags.GENERIC),
999+
DecoratorFlags.BUILTIN
1000+
));
9951001

9961002
// The following types might not be enabled by compiler options, so the
9971003
// compiler needs to check this condition whenever such a value is created

src/resolver.ts

+55-56
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ export class Resolver extends DiagnosticEmitter {
296296
if (text == CommonNames.indexof) return this.resolveBuiltinIndexofType(node, ctxElement, ctxTypes, reportMode);
297297
if (text == CommonNames.valueof) return this.resolveBuiltinValueofType(node, ctxElement, ctxTypes, reportMode);
298298
if (text == CommonNames.returnof) return this.resolveBuiltinReturnTypeType(node, ctxElement, ctxTypes, reportMode);
299+
if (text == CommonNames.nonnull) return this.resolveBuiltinNotNullableType(node, ctxElement, ctxTypes, reportMode);
299300
}
300301

301302
// Resolve normally
@@ -438,19 +439,9 @@ export class Resolver extends DiagnosticEmitter {
438439
/** How to proceed with eventual diagnostics. */
439440
reportMode: ReportMode = ReportMode.REPORT
440441
): Type | null {
441-
var typeArgumentNodes = node.typeArguments;
442-
if (!typeArgumentNodes || typeArgumentNodes.length != 1) {
443-
if (reportMode == ReportMode.REPORT) {
444-
let numTypeArguments = 0;
445-
if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length;
446-
this.error(
447-
DiagnosticCode.Expected_0_type_arguments_but_got_1,
448-
node.range, "1", numTypeArguments.toString()
449-
);
450-
}
451-
return null;
452-
}
453-
var typeArgument = this.resolveType(typeArgumentNodes[0], ctxElement, ctxTypes, reportMode);
442+
const typeArgumentNode = this.ensureOneTypeArgument(node, reportMode);
443+
if (!typeArgumentNode) return null;
444+
var typeArgument = this.resolveType(typeArgumentNode, ctxElement, ctxTypes, reportMode);
454445
if (!typeArgument) return null;
455446
switch (typeArgument.kind) {
456447
case TypeKind.I8:
@@ -483,26 +474,16 @@ export class Resolver extends DiagnosticEmitter {
483474
/** How to proceed with eventual diagnostics. */
484475
reportMode: ReportMode = ReportMode.REPORT
485476
): Type | null {
486-
var typeArgumentNodes = node.typeArguments;
487-
if (!typeArgumentNodes || typeArgumentNodes.length != 1) {
488-
if (reportMode == ReportMode.REPORT) {
489-
let numTypeArguments = 0;
490-
if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length;
491-
this.error(
492-
DiagnosticCode.Expected_0_type_arguments_but_got_1,
493-
node.range, "1", numTypeArguments.toString()
494-
);
495-
}
496-
return null;
497-
}
498-
var typeArgument = this.resolveType(typeArgumentNodes[0], ctxElement, ctxTypes, reportMode);
477+
const typeArgumentNode = this.ensureOneTypeArgument(node, reportMode);
478+
if (!typeArgumentNode) return null;
479+
var typeArgument = this.resolveType(typeArgumentNode, ctxElement, ctxTypes, reportMode);
499480
if (!typeArgument) return null;
500481
var classReference = typeArgument.classReference;
501482
if (!classReference) {
502483
if (reportMode == ReportMode.REPORT) {
503484
this.error(
504485
DiagnosticCode.Index_signature_is_missing_in_type_0,
505-
typeArgumentNodes[0].range, typeArgument.toString()
486+
typeArgumentNode.range, typeArgument.toString()
506487
);
507488
}
508489
return null;
@@ -520,7 +501,7 @@ export class Resolver extends DiagnosticEmitter {
520501
if (reportMode == ReportMode.REPORT) {
521502
this.error(
522503
DiagnosticCode.Index_signature_is_missing_in_type_0,
523-
typeArgumentNodes[0].range, typeArgument.toString()
504+
typeArgumentNode.range, typeArgument.toString()
524505
);
525506
}
526507
return null;
@@ -536,19 +517,9 @@ export class Resolver extends DiagnosticEmitter {
536517
/** How to proceed with eventual diagnostics. */
537518
reportMode: ReportMode = ReportMode.REPORT
538519
): Type | null {
539-
var typeArgumentNodes = node.typeArguments;
540-
if (!typeArgumentNodes || typeArgumentNodes.length != 1) {
541-
let numTypeArguments = 0;
542-
if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length;
543-
if (reportMode == ReportMode.REPORT) {
544-
this.error(
545-
DiagnosticCode.Expected_0_type_arguments_but_got_1,
546-
node.range, "1", numTypeArguments.toString()
547-
);
548-
}
549-
return null;
550-
}
551-
var typeArgument = this.resolveType(typeArgumentNodes[0], ctxElement, ctxTypes, reportMode);
520+
const typeArgumentNode = this.ensureOneTypeArgument(node, reportMode);
521+
if (!typeArgumentNode) return null;
522+
var typeArgument = this.resolveType(typeArgumentNode, ctxElement, ctxTypes, reportMode);
552523
if (!typeArgument) return null;
553524
var classReference = typeArgument.getClassOrWrapper(this.program);
554525
if (classReference) {
@@ -558,7 +529,7 @@ export class Resolver extends DiagnosticEmitter {
558529
if (reportMode == ReportMode.REPORT) {
559530
this.error(
560531
DiagnosticCode.Index_signature_is_missing_in_type_0,
561-
typeArgumentNodes[0].range, typeArgument.toString()
532+
typeArgumentNode.range, typeArgument.toString()
562533
);
563534
}
564535
return null;
@@ -574,31 +545,39 @@ export class Resolver extends DiagnosticEmitter {
574545
/** How to proceed with eventualy diagnostics. */
575546
reportMode: ReportMode = ReportMode.REPORT
576547
): Type | null {
577-
var typeArgumentNodes = node.typeArguments;
578-
if (!typeArgumentNodes || typeArgumentNodes.length != 1) {
579-
if (reportMode == ReportMode.REPORT) {
580-
let numTypeArguments = 0;
581-
if (typeArgumentNodes) numTypeArguments = typeArgumentNodes.length;
582-
this.error(
583-
DiagnosticCode.Expected_0_type_arguments_but_got_1,
584-
node.range, "1", numTypeArguments.toString()
585-
);
586-
}
587-
return null;
588-
}
589-
var typeArgument = this.resolveType(typeArgumentNodes[0], ctxElement, ctxTypes, reportMode);
548+
const typeArgumentNode = this.ensureOneTypeArgument(node, reportMode);
549+
if (!typeArgumentNode) return null;
550+
var typeArgument = this.resolveType(typeArgumentNode, ctxElement, ctxTypes, reportMode);
590551
if (!typeArgument) return null;
591552
var signatureReference = typeArgument.getSignature();
592553
if (signatureReference) return signatureReference.returnType;
593554
if (reportMode == ReportMode.REPORT) {
594555
this.error(
595556
DiagnosticCode.Type_0_has_no_call_signatures,
596-
typeArgumentNodes[0].range, typeArgument.toString()
557+
typeArgumentNode.range, typeArgument.toString()
597558
);
598559
}
599560
return null;
600561
}
601562

563+
private resolveBuiltinNotNullableType(
564+
/** The type to resolve. */
565+
node: NamedTypeNode,
566+
/** Contextual element. */
567+
ctxElement: Element,
568+
/** Contextual types, i.e. `T`. */
569+
ctxTypes: Map<string,Type> | null = null,
570+
/** How to proceed with eventual diagnostics. */
571+
reportMode: ReportMode = ReportMode.REPORT
572+
): Type | null {
573+
const typeArgumentNode = this.ensureOneTypeArgument(node, reportMode);
574+
if (!typeArgumentNode) return null;
575+
var typeArgument = this.resolveType(typeArgumentNode, ctxElement, ctxTypes, reportMode);
576+
if (!typeArgument) return null;
577+
if (!typeArgument.isNullableReference) return typeArgument;
578+
return typeArgument.nonNullableType;
579+
}
580+
602581
/** Resolves a type name to the program element it refers to. */
603582
resolveTypeName(
604583
/** The type name to resolve. */
@@ -3362,4 +3341,24 @@ export class Resolver extends DiagnosticEmitter {
33623341
}
33633342
return instance;
33643343
}
3344+
3345+
private ensureOneTypeArgument(
3346+
/** The type to resolve. */
3347+
node: NamedTypeNode,
3348+
/** How to proceed with eventual diagnostics. */
3349+
reportMode: ReportMode = ReportMode.REPORT
3350+
): TypeNode | null {
3351+
var typeArgumentNodes = node.typeArguments;
3352+
let numTypeArguments = 0;
3353+
if (!typeArgumentNodes || (numTypeArguments = typeArgumentNodes.length) != 1) {
3354+
if (reportMode == ReportMode.REPORT) {
3355+
this.error(
3356+
DiagnosticCode.Expected_0_type_arguments_but_got_1,
3357+
node.range, "1", numTypeArguments.toString()
3358+
);
3359+
}
3360+
return null;
3361+
}
3362+
return typeArgumentNodes[0];
3363+
}
33653364
}

std/assembly/compat.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export type ReturnType<T> = returnof<T>;
2+
export type NonNullable<T> = nonnull<T>;

std/assembly/index.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,10 @@ declare type valueof<T extends unknown[]> = T[0];
13141314
declare type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
13151315
/** A special type evaluated to the return type of T if T is a callable function. */
13161316
declare type returnof<T extends (...args: any) => any> = ReturnType<T>;
1317+
/** A special type that excludes null and undefined from T. */
1318+
declare type NonNullable<T> = T extends null | undefined ? never : T;
1319+
/** A special type that excludes null and undefined from T. */
1320+
declare type nonnull<T> = NonNullable<T>;
13171321

13181322
/** Pseudo-class representing the backing class of integer types. */
13191323
declare class _Integer {

tests/asconfig/complicated/asconfig.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
"initialMemory": 100,
1515
"enable": ["simd"]
1616
}
17-
}
17+
}

tests/asconfig/extends/expected.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
"noAssert": true,
66
"enable": ["simd"]
77
}
8-
}
8+
}

tests/asconfig/target/expected.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
"exportRuntime": false,
44
"noAssert": true
55
}
6-
}
6+
}

0 commit comments

Comments
 (0)