@helios-lang/compiler
Version:
Helios is a Domain Specific Language that compiles to Plutus-Core (i.e. Cardano on-chain validator scripts). Helios is a non-Haskell alternative to Plutus. With this library you can compile Helios scripts and build Cardano transactions, all you need to bu
1,154 lines (1,079 loc) • 39.5 kB
JavaScript
import {
makeErrorCollector,
makeTypeError,
makeWord
} from "@helios-lang/compiler-utils"
import { expectDefined } from "@helios-lang/type-utils"
import {
AllType,
ArgType,
Common,
FuncType,
GenericEnumMemberType,
GenericType,
VoidType,
applyTypes,
registerExpandTupleType,
registerMakeListType,
registerMakeMapType
} from "./common.js"
import { Parameter } from "./Parameter.js"
import { ParametricFunc } from "./ParametricFunc.js"
import {
AnyTypeClass,
GenericParametricType,
GenericParametricEnumMemberType,
ParametricType,
DefaultTypeClass,
SummableTypeClass
} from "./parametric.js"
import { FTPP, TTPP } from "../codegen/ParametricName.js"
import {
BoolType,
ByteArrayType,
IntType,
RealType,
StringType,
genCommonInstanceMembers,
genCommonTypeMembers
} from "./primitives.js"
/**
* @import { Site } from "@helios-lang/compiler-utils"
* @import { TypeCheckContext } from "../index.js"
* @typedef {import("./common.js").DataType} DataType
* @typedef {import("./common.js").EnumMemberType} EnumMemberType
* @typedef {import("./common.js").GenericTypeProps} GenericTypeProps
* @typedef {import("./common.js").GenericEnumMemberTypeProps} GenericEnumMemberTypeProps
* @typedef {import("./common.js").Named} Named
* @typedef {import("./common.js").Parametric} Parametric
* @typedef {import("./common.js").Type} Type
* @typedef {import("./common.js").Typed} Typed
* @typedef {import("./common.js").InstanceMembers} InstanceMembers
* @typedef {import("./common.js").TypeMembers} TypeMembers
* @typedef {import("./common.js").InferenceMap} InferenceMap
*/
/**
* @param {Type[]} itemTypes
* @returns {Type}
*/
export function IteratorType$(itemTypes) {
const props = {
name: `Iterator[${itemTypes.map((it) => it.toString()).join(", ")}]`,
path: `__helios__iterator__${itemTypes.length}`,
genInstanceMembers: (self) => {
// Note: to_list and to_map can't be part of Iterator because type information is lost (eg. we can map to an iterator over functions)
const itemType =
itemTypes.length == 1 ? itemTypes[0] : TupleType$(itemTypes)
const members = {
all: new FuncType(
[new FuncType(itemTypes, BoolType)],
BoolType
),
any: new FuncType(
[new FuncType(itemTypes, BoolType)],
BoolType
),
drop: new FuncType([IntType], self),
filter: new FuncType([new FuncType(itemTypes, BoolType)], self),
find: new FuncType(
[new FuncType(itemTypes, BoolType)],
itemType
),
for_each: new FuncType(
[new FuncType(itemTypes, new VoidType())],
new VoidType()
),
fold: (() => {
const a = new Parameter("a", `${FTPP}0`, new AnyTypeClass())
return new ParametricFunc(
[a],
new FuncType(
[
new FuncType([a.ref].concat(itemTypes), a.ref),
a.ref
],
a.ref
)
)
})(),
head: itemType,
get: new FuncType([IntType], itemType),
get_singleton: new FuncType([], itemType),
is_empty: new FuncType([], BoolType),
map: (() => {
const a = new Parameter("a", `${FTPP}0`, new AnyTypeClass())
return new ParametricFunc(
[a],
new FuncType(
[new FuncType(itemTypes, a.ref)],
IteratorType$([a.ref])
)
)
})(),
map2: (() => {
const a = new Parameter("a", `${FTPP}0`, new AnyTypeClass())
const b = new Parameter("b", `${FTPP}0`, new AnyTypeClass())
return new ParametricFunc(
[a, b],
new FuncType(
[
new FuncType(
itemTypes,
TupleType$([a.ref, b.ref])
)
],
IteratorType$([a.ref, b.ref])
)
)
})(),
prepend: new FuncType(itemTypes, self),
tail: self,
take: new FuncType([IntType], self)
}
if (itemTypes.length < 10) {
members.zip = (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new DefaultTypeClass()
)
return new ParametricFunc(
[a],
new FuncType(
[ListType$(a.ref)],
IteratorType$(itemTypes.concat([a.ref]))
)
)
})()
}
return members
},
genTypeMembers: (self) => ({})
}
// if any of the item type is parametric, this return type must also be parametric so that the item type inference methods are called correctly
// (i.e. the inference method of this Iterator type calls the inference methods of the itemtypes)
return itemTypes.some((it) => it.isParametric())
? new GenericParametricType(props)
: new GenericType(props)
}
/**
* @implements {DataType}
*/
export class TupleType extends GenericType {
/**
* @private
* @readonly
* @type {Type[]}
*/
_itemTypes
/**
* @param {GenericTypeProps} props
* @param {Type[]} itemTypes
*/
constructor(props, itemTypes) {
super(props)
this._itemTypes = itemTypes
}
/**
* @type {Type[]}
*/
get itemTypes() {
return this._itemTypes
}
/**
* @param {Type} other
* @returns {boolean}
*/
isBaseOf(other) {
if (other instanceof TupleType) {
return (
other._itemTypes.length == this._itemTypes.length &&
this._itemTypes.every((it, i) =>
it.isBaseOf(other._itemTypes[i])
)
)
} else {
return false
}
}
/**
* @param {TypeCheckContext} ctx
* @param {Site} site
* @param {InferenceMap} map
* @param {null | Type} type
* @returns {Type}
*/
infer(ctx, site, map, type) {
if (!this._itemTypes.some((it) => it.isParametric())) {
return this
}
if (!type) {
const itemTypes = this._itemTypes.map((it) =>
it.infer(ctx, site, map, null)
)
return TupleType$(itemTypes)
} else if (
type instanceof TupleType &&
this._itemTypes.length == type._itemTypes.length
) {
const itemTypes = this._itemTypes.map((it, i) =>
it.infer(ctx, site, map, type._itemTypes[i])
)
return TupleType$(itemTypes)
}
ctx.errors.type(
site,
`unable to infer type of ${this.toString()} (${type instanceof TupleType} ${type instanceof GenericType})`
)
return new AllType()
}
}
/**
* TODO: rename DataType to something else
* @param {Type} type
* @return {boolean}
*/
export function isDataType(type) {
const dt = type.asDataType
if (!dt) {
return false
}
// no need to check for primitives
if (
dt == IntType ||
dt == StringType ||
dt == ByteArrayType ||
dt == BoolType ||
dt == RealType
) {
return true
}
const dataTypeClass = new DefaultTypeClass()
return dataTypeClass.isImplementedBy(dt)
}
/**
* @param {Type[]} itemTypes
* @param {boolean | null} isAllDataTypes - if the all the itemTypes are known datatypes, then don't check that here (could lead to infinite recursion)
* @returns {Type}
*/
export function TupleType$(itemTypes, isAllDataTypes = null) {
const isData = isAllDataTypes
? isAllDataTypes
: itemTypes.every((it) => {
return isDataType(it)
})
/**
* @type {GenericTypeProps}
*/
const props = {
name: `(${itemTypes.map((it) => it.toString()).join(", ")})`,
path: `__helios__tuple[${itemTypes.map((it) => (it.asDataType ? it.asDataType.path : "__helios__func")).join("@")}]`,
genTypeSchema: (self) => {
if (isData) {
return {
kind: "tuple",
itemTypes: itemTypes.map((it) =>
expectDefined(it.asDataType).toSchema()
)
}
} else {
throw new Error(
`TypeSchema not available for ${self.toString()}`
)
}
},
genInstanceMembers: (self) => {
const members = isData ? genCommonInstanceMembers(self) : {}
const getters = ["first", "second", "third", "fourth", "fifth"]
for (let i = 0; i < 5 && i < itemTypes.length; i++) {
const key = getters[i]
members[key] = itemTypes[i]
}
const a = new Parameter("a", `${FTPP}0`, new AnyTypeClass())
members.__to_func = new ParametricFunc(
[a],
new FuncType([new FuncType(itemTypes, a.ref)], a.ref)
)
return members
},
genTypeMembers: (self) => {
return isData ? genCommonTypeMembers(self) : {}
}
}
return new TupleType(props, itemTypes)
}
/**
* Returns null if `type` isn't a tuple
* @param {Type} type
* @returns {Type[] | undefined}
*/
export function getTupleItemTypes(type) {
if (type instanceof TupleType) {
return type.itemTypes
} else {
return undefined
}
}
// dirty hack to be able to expand tuples in functions
registerExpandTupleType(getTupleItemTypes)
/**
* Expand tuples in posArgs, if that matches argTypes better
* @param {FuncType} funcType
* @param {Typed[]} posArgs
* @returns {Typed[]}
*/
export function expandTuplesInPosArgs(funcType, posArgs) {
posArgs = posArgs.slice()
let arg = posArgs.shift()
/**
* @type {Typed[]}
*/
let result = []
let i = 0
while (arg) {
if (
i < funcType.origArgTypes.length &&
Common.instanceOf(arg, funcType.origArgTypes[i].type)
) {
result.push(arg)
i++
} else {
const tupleItemTypes = getTupleItemTypes(arg.type)
if (
tupleItemTypes &&
tupleItemTypes.every(
(tit, j) =>
i + j < funcType.origArgTypes.length &&
Common.instanceOf(
tit.toTyped(),
funcType.origArgTypes[i + j].type
)
)
) {
result = result.concat(
tupleItemTypes.map((tit) => tit.toTyped())
)
i += tupleItemTypes.length
} else {
// mismatched type, but don't throw error here because better error will be thrown later
result.push(arg)
i++
}
}
arg = posArgs.shift()
}
return result
}
/**
* Builtin list type
* @type {Parametric}
*/
export const ListType = new ParametricType({
name: "[]",
parameters: [new Parameter("ItemType", `${TTPP}0`, new DefaultTypeClass())],
apply: ([itemType_]) => {
const itemType = expectDefined(itemType_.asDataType)
/**
* @type {GenericTypeProps}
*/
const props = {
name: `[]${itemType.toString()}`,
path: `__helios__list[${itemType.path}]`,
genTypeSchema: (self, parents) => ({
kind: /** @type {const} */ ("list"),
itemType: expectDefined(itemType.toSchema(parents))
}),
genInstanceMembers: (self) => {
/**
* @type {InstanceMembers}
*/
const specialMembers = {}
if (new SummableTypeClass().isImplementedBy(itemType)) {
specialMembers.sum = new FuncType([], itemType)
} else if (StringType.isBaseOf(itemType)) {
specialMembers.join = new FuncType(
[
new ArgType(
makeWord({ value: "separator" }),
StringType,
true
)
],
StringType
)
} else if (ByteArrayType.isBaseOf(itemType)) {
specialMembers.join = new FuncType(
[
new ArgType(
makeWord({ value: "separator" }),
ByteArrayType,
true
)
],
ByteArrayType
)
} else if (itemType.asNamed?.name.startsWith("[]")) {
specialMembers.flatten = new FuncType([], itemType)
}
return {
...genCommonInstanceMembers(self),
...specialMembers,
all: new FuncType(
[new FuncType([itemType], BoolType)],
BoolType
),
any: new FuncType(
[new FuncType([itemType], BoolType)],
BoolType
),
append: new FuncType([itemType], self),
drop: new FuncType([IntType], self),
drop_end: new FuncType([IntType], self),
filter: new FuncType(
[new FuncType([itemType], BoolType)],
self
),
find: new FuncType(
[new FuncType([itemType], BoolType)],
itemType
),
find_index: new FuncType(
[new FuncType([itemType], BoolType)],
IntType
),
find_safe: new FuncType(
[new FuncType([itemType], BoolType)],
OptionType$(itemType)
),
fold: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new AnyTypeClass()
)
return new ParametricFunc(
[a],
new FuncType(
[new FuncType([a.ref, itemType], a.ref), a.ref],
a.ref
)
)
})(),
fold2: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new AnyTypeClass()
)
const b = new Parameter(
"b",
`${FTPP}0`,
new AnyTypeClass()
)
return new ParametricFunc(
[a, b],
new FuncType(
[
new FuncType(
[a.ref, b.ref, itemType],
TupleType$([a.ref, b.ref])
),
a.ref,
b.ref
],
TupleType$([a.ref, b.ref])
)
)
})(),
fold3: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new AnyTypeClass()
)
const b = new Parameter(
"b",
`${FTPP}0`,
new AnyTypeClass()
)
const c = new Parameter(
"c",
`${FTPP}0`,
new AnyTypeClass()
)
return new ParametricFunc(
[a, b, c],
new FuncType(
[
new FuncType(
[a.ref, b.ref, c.ref, itemType],
TupleType$([a.ref, b.ref, c.ref])
),
a.ref,
b.ref,
c.ref
],
TupleType$([a.ref, b.ref, c.ref])
)
)
})(),
fold_lazy: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new AnyTypeClass()
)
return new ParametricFunc(
[a],
new FuncType(
[
new FuncType(
[itemType, new FuncType([], a.ref)],
a.ref
),
a.ref
],
a.ref
)
)
})(),
fold2_lazy: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new AnyTypeClass()
)
const b = new Parameter(
"b",
`${FTPP}0`,
new AnyTypeClass()
)
return new ParametricFunc(
[a, b],
new FuncType(
[
new FuncType(
[
itemType,
new FuncType(
[],
TupleType$([a.ref, b.ref])
)
],
TupleType$([a.ref, b.ref])
),
a.ref,
b.ref
],
TupleType$([a.ref, b.ref])
)
)
})(),
for_each: new FuncType(
[new FuncType([itemType], new VoidType())],
new VoidType()
),
get: new FuncType([IntType], itemType),
get_singleton: new FuncType([], itemType),
head: itemType,
is_empty: new FuncType([], BoolType),
length: IntType,
map: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new DefaultTypeClass()
)
return new ParametricFunc(
[a],
new FuncType(
[new FuncType([itemType], a.ref)],
ListType$(a.ref)
)
)
})(),
map_option: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new DefaultTypeClass()
)
return new ParametricFunc(
[a],
new FuncType(
[new FuncType([itemType], OptionType$(a.ref))],
ListType$(a.ref)
)
)
})(),
prepend: new FuncType([itemType], self),
set: new FuncType([IntType, itemType], self),
sort: new FuncType(
[new FuncType([itemType, itemType], BoolType)],
self
),
split_at: new FuncType(
[IntType],
TupleType$([self, self], true)
),
tail: self,
take: new FuncType([IntType], self),
take_end: new FuncType([IntType], self),
to_iterator: new FuncType([], IteratorType$([itemType])),
zip: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new DefaultTypeClass()
)
return new ParametricFunc(
[a],
new FuncType(
[ListType$(a.ref)],
IteratorType$([itemType, a.ref])
)
)
})()
}
},
genTypeMembers: (self) => ({
...genCommonTypeMembers(self),
__add: new FuncType([self, self], self),
new: new FuncType(
[IntType, new FuncType([IntType], itemType)],
self
),
new_const: new FuncType([IntType, itemType], self),
from_iterator: new FuncType([IteratorType$([itemType])], self)
})
}
return itemType_.isParametric()
? new GenericParametricType(props)
: new GenericType(props)
}
})
/**
* @param {Type} itemType
* @returns {DataType}
*/
export function ListType$(itemType) {
const errors = makeErrorCollector()
const result = applyTypes({ errors }, ListType, itemType)
errors.throw()
return result
}
registerMakeListType(ListType$)
/**
* Builtin map type (in reality list of key-value pairs)
* @internal
* @type {Parametric}
*/
export const MapType = new ParametricType({
name: "Map",
parameters: [
new Parameter("KeyType", `${TTPP}0`, new DefaultTypeClass()),
new Parameter("ValueType", `${TTPP}1`, new DefaultTypeClass())
],
apply: ([keyType_, valueType_]) => {
const keyType = expectDefined(keyType_.asDataType)
const valueType = expectDefined(valueType_.asDataType)
/**
* @type {GenericTypeProps}
*/
const props = {
name: `Map[${keyType.toString()}]${valueType.toString()}`,
path: `__helios__map[${keyType.path}{valueType.path}]`,
genTypeSchema: (self, parents) => ({
kind: /** @type {const} */ ("map"),
keyType: expectDefined(keyType.toSchema(parents)),
valueType: expectDefined(valueType.toSchema(parents))
}),
genInstanceMembers: (self) => ({
...genCommonInstanceMembers(self),
all: new FuncType(
[new FuncType([keyType, valueType], BoolType)],
BoolType
),
all_keys: new FuncType(
[new FuncType([keyType], BoolType)],
BoolType
),
all_values: new FuncType(
[new FuncType([valueType], BoolType)],
BoolType
),
any: new FuncType(
[new FuncType([keyType, valueType], BoolType)],
BoolType
),
any_key: new FuncType(
[new FuncType([keyType], BoolType)],
BoolType
),
any_value: new FuncType(
[new FuncType([valueType], BoolType)],
BoolType
),
append: new FuncType([keyType, valueType], self),
delete: new FuncType([keyType], self),
filter: new FuncType(
[new FuncType([keyType, valueType], BoolType)],
self
),
find: new FuncType(
[new FuncType([keyType, valueType], BoolType)],
TupleType$([keyType, valueType], true)
),
find_key: new FuncType(
[new FuncType([keyType], BoolType)],
keyType
),
find_key_safe: new FuncType(
[new FuncType([keyType], BoolType)],
OptionType$(keyType)
),
// TODO: convert return value of find_safe to an OptionType of a TupleType (requires changing the way options work internally)
find_safe: new FuncType(
[new FuncType([keyType, valueType], BoolType)],
TupleType$(
[
new FuncType([], TupleType$([keyType, valueType])),
BoolType
],
false
)
),
find_value: new FuncType(
[new FuncType([valueType], BoolType)],
valueType
),
find_value_safe: new FuncType(
[new FuncType([valueType], BoolType)],
OptionType$(valueType)
),
fold: (() => {
const a = new Parameter("a", `${FTPP}0`, new AnyTypeClass())
return new ParametricFunc(
[a],
new FuncType(
[
new FuncType(
[a.ref, keyType, valueType],
a.ref
),
a.ref
],
a.ref
)
)
})(),
fold_lazy: (() => {
const a = new Parameter("a", `${FTPP}0`, new AnyTypeClass())
return new ParametricFunc(
[a],
new FuncType(
[
new FuncType(
[
keyType,
valueType,
new FuncType([], a.ref)
],
a.ref
),
a.ref
],
a.ref
)
)
})(),
fold_with_list: (() => {
const a = new Parameter("a", `${FTPP}0`, new AnyTypeClass())
const b = new Parameter(
"b",
`${FTPP}1`,
new DefaultTypeClass()
)
return new ParametricFunc(
[a, b],
new FuncType(
[
new FuncType(
[a.ref, keyType, valueType, b.ref],
a.ref
),
a.ref,
ListType$(b.ref)
],
a.ref
)
)
})(),
fold2: (() => {
const a = new Parameter("a", `${FTPP}0`, new AnyTypeClass())
const b = new Parameter("b", `${FTPP}0`, new AnyTypeClass())
return new ParametricFunc(
[a, b],
new FuncType(
[
new FuncType(
[a.ref, b.ref, keyType, valueType],
TupleType$([a.ref, b.ref])
),
a.ref,
b.ref
],
TupleType$([a.ref, b.ref])
)
)
})(),
for_each: new FuncType(
[new FuncType([keyType, valueType], new VoidType())],
new VoidType()
),
get: new FuncType([keyType], valueType),
get_safe: new FuncType([keyType], OptionType$(valueType)),
head: TupleType$([keyType, valueType], true),
head_key: keyType,
head_value: valueType,
is_empty: new FuncType([], BoolType),
length: IntType,
map: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new DefaultTypeClass()
)
const b = new Parameter(
"b",
`${FTPP}1`,
new DefaultTypeClass()
)
return new ParametricFunc(
[a, b],
new FuncType(
[
new FuncType(
[keyType, valueType],
TupleType$([a.ref, b.ref], true)
)
],
MapType$(a.ref, b.ref)
)
)
})(),
to_list: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new DefaultTypeClass()
)
return new ParametricFunc(
[a],
new FuncType(
[new FuncType([keyType, valueType], a.ref)],
ListType$(a.ref)
)
)
})(),
prepend: new FuncType([keyType, valueType], self),
set: new FuncType([keyType, valueType], self),
sort: new FuncType(
[
new FuncType(
[keyType, valueType, keyType, valueType],
BoolType
)
],
self
),
tail: self,
to_iterator: new FuncType(
[],
IteratorType$([keyType, valueType])
),
update: new FuncType(
[keyType, new FuncType([valueType], valueType)],
self
),
update_safe: new FuncType(
[keyType, new FuncType([valueType], valueType)],
self
)
}),
genTypeMembers: (self) => ({
...genCommonTypeMembers(self),
__add: new FuncType([self, self], self),
from_iterator: new FuncType(
[IteratorType$([keyType, valueType])],
self
)
})
}
return keyType.isParametric() || valueType.isParametric()
? new GenericParametricType(props)
: new GenericType(props)
}
})
/**
* @param {Type} keyType
* @param {Type} valueType
* @returns {DataType}
*/
export function MapType$(keyType, valueType) {
const errors = makeErrorCollector()
const result = applyTypes({ errors }, MapType, keyType, valueType)
errors.throw()
return result
}
registerMakeMapType(MapType$)
/**
* Builtin option type
* @type {Parametric}
*/
const OptionType = new ParametricType({
name: "Option",
parameters: [new Parameter("SomeType", `${TTPP}0`, new DefaultTypeClass())],
apply: ([someType_]) => {
const someType = expectDefined(someType_.asDataType)
const someTypePath = someType.path
/**
* @type {null | EnumMemberType}
*/
let NoneType = null
/**
* @type {null | EnumMemberType}
*/
let SomeType = null
/**
* @type {GenericTypeProps}
*/
const appliedOptionTypeProps = {
name: `Option[${someType.toString()}]`,
path: `__helios__option[${someTypePath}]`,
genTypeSchema: (self, parents) => ({
kind: "option",
someType: expectDefined(someType.toSchema(parents))
}),
genInstanceMembers: (self) => ({
...genCommonInstanceMembers(self),
is_some: new FuncType([], BoolType),
map: (() => {
const a = new Parameter(
"a",
`${FTPP}0`,
new DefaultTypeClass()
)
return new ParametricFunc(
[a],
new FuncType(
[new FuncType([someType], a.ref)],
OptionType$(a.ref)
)
)
})(),
unwrap: new FuncType([], someType)
}),
genTypeMembers: (self) => ({
...genCommonTypeMembers(self),
None: expectDefined(NoneType),
Some: expectDefined(SomeType)
})
}
const somePath = `__helios__option[${someTypePath}]__some`
/**
* @type {Omit<GenericEnumMemberTypeProps, "parentType">}
*/
const someTypeProps = {
name: "Some",
constrIndex: 0,
fieldNames: ["some"],
path: somePath,
genTypeSchema: (self, parents) => ({
kind: "variant",
tag: 0,
name: "Some",
id: somePath,
fieldTypes: [
{
name: "some",
type: someType.toSchema(parents)
}
]
}),
genInstanceMembers: (self) => ({
...genCommonInstanceMembers(self),
some: someType
}),
genTypeMembers: (self) => ({
...genCommonTypeMembers(self),
__is: new FuncType(
[expectDefined(self.asEnumMemberType).parentType],
BoolType
)
})
}
const nonePath = `__helios__option[${someTypePath}]__none`
/**
* @type {Omit<GenericEnumMemberTypeProps, "parentType">}
*/
const noneTypeProps = {
name: "None",
constrIndex: 1,
path: nonePath,
genTypeSchema: (self, parents) => ({
kind: "variant",
tag: 1,
name: "None",
id: nonePath,
fieldTypes: []
}),
genInstanceMembers: (self) => ({
...genCommonInstanceMembers(self)
}),
genTypeMembers: (self) => ({
...genCommonTypeMembers(self),
__is: new FuncType(
[expectDefined(self.asEnumMemberType).parentType],
BoolType
)
})
}
if (someType.isParametric()) {
const AppliedOptionType = new GenericParametricType(
appliedOptionTypeProps
)
SomeType = new GenericParametricEnumMemberType({
...someTypeProps,
parentType: AppliedOptionType
})
NoneType = new GenericParametricEnumMemberType({
...noneTypeProps,
parentType: AppliedOptionType
})
return AppliedOptionType
} else {
const AppliedOptionType = new GenericType(appliedOptionTypeProps)
SomeType = new GenericEnumMemberType({
...someTypeProps,
parentType: AppliedOptionType
})
NoneType = new GenericEnumMemberType({
...noneTypeProps,
parentType: AppliedOptionType
})
return AppliedOptionType
}
}
})
/**
* @internal
* @param {Type} someType
* @returns {DataType}
*/
export function OptionType$(someType) {
const errors = makeErrorCollector()
const result = applyTypes({ errors }, OptionType, someType)
errors.throw()
return result
}