Skip to content

Commit

Permalink
chore(typeEvaluator): rename mapConcrete to mapNode
Browse files Browse the repository at this point in the history
  • Loading branch information
sgulseth committed Aug 23, 2024
1 parent 41679a3 commit 494c393
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 54 deletions.
62 changes: 31 additions & 31 deletions src/typeEvaluator/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type {FuncCallNode} from '../nodeTypes'
import {Scope} from './scope'
import {walk} from './typeEvaluate'
import {mapConcrete, nullUnion} from './typeHelpers'
import {mapNode, nullUnion} from './typeHelpers'
import type {NullTypeNode, TypeNode} from './types'

function unionWithoutNull(unionTypeNode: TypeNode): TypeNode {
Expand All @@ -21,15 +21,15 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'array.compact': {
const arg = walk({node: node.args[0], scope})

return mapConcrete(arg, scope, (arg) => {
return mapNode(arg, scope, (arg) => {
if (arg.type === 'unknown') {
return nullUnion({type: 'array', of: {type: 'unknown'}})
}
if (arg.type !== 'array') {
return {type: 'null'}
}

const of = mapConcrete(arg.of, scope, (of) => of)
const of = mapNode(arg.of, scope, (of) => of)
return {
type: 'array',
of: unionWithoutNull(of),
Expand All @@ -41,16 +41,16 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
const arrayArg = walk({node: node.args[0], scope})
const sepArg = walk({node: node.args[1], scope})

return mapConcrete(arrayArg, scope, (arrayArg) =>
mapConcrete(sepArg, scope, (sepArg) => {
return mapNode(arrayArg, scope, (arrayArg) =>
mapNode(sepArg, scope, (sepArg) => {
if (arrayArg.type === 'unknown' || sepArg.type === 'unknown') {
return nullUnion({type: 'string'})
}
if (arrayArg.type !== 'array' || sepArg.type !== 'string') {
return {type: 'null'}
}

return mapConcrete(arrayArg.of, scope, (of) => {
return mapNode(arrayArg.of, scope, (of) => {
if (of.type === 'unknown') {
return nullUnion({type: 'string'})
}
Expand All @@ -68,7 +68,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'array.unique': {
const arg = walk({node: node.args[0], scope})

return mapConcrete(arg, scope, (arg) => {
return mapNode(arg, scope, (arg) => {
if (arg.type === 'unknown') {
return nullUnion({type: 'array', of: {type: 'unknown'}})
}
Expand All @@ -83,7 +83,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'global.lower': {
const arg = walk({node: node.args[0], scope})

return mapConcrete(arg, scope, (arg) => {
return mapNode(arg, scope, (arg) => {
if (arg.type === 'unknown') {
return nullUnion({type: 'string'})
}
Expand All @@ -103,7 +103,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'global.upper': {
const arg = walk({node: node.args[0], scope})

return mapConcrete(arg, scope, (arg) => {
return mapNode(arg, scope, (arg) => {
if (arg.type === 'unknown') {
return nullUnion({type: 'string'})
}
Expand All @@ -130,7 +130,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
}
case 'global.path': {
const arg = walk({node: node.args[0], scope})
return mapConcrete(arg, scope, (arg) => {
return mapNode(arg, scope, (arg) => {
if (arg.type === 'unknown') {
return nullUnion({type: 'string'})
}
Expand Down Expand Up @@ -168,7 +168,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'global.count': {
const arg = walk({node: node.args[0], scope})

return mapConcrete(arg, scope, (arg) => {
return mapNode(arg, scope, (arg) => {
if (arg.type === 'unknown') {
return nullUnion({type: 'string'})
}
Expand All @@ -184,7 +184,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'global.dateTime': {
const arg = walk({node: node.args[0], scope})

return mapConcrete(arg, scope, (arg) => {
return mapNode(arg, scope, (arg) => {
if (arg.type === 'unknown') {
return nullUnion({type: 'string'})
}
Expand All @@ -200,7 +200,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'global.length': {
const arg = walk({node: node.args[0], scope})

return mapConcrete(arg, scope, (arg) => {
return mapNode(arg, scope, (arg) => {
if (arg.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand All @@ -219,7 +219,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'global.round': {
const numNode = walk({node: node.args[0], scope})

return mapConcrete(numNode, scope, (num) => {
return mapNode(numNode, scope, (num) => {
if (num.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand All @@ -229,7 +229,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
}
if (node.args.length === 2) {
const precisionNode = walk({node: node.args[1], scope})
return mapConcrete(precisionNode, scope, (precision) => {
return mapNode(precisionNode, scope, (precision) => {
if (precision.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand All @@ -248,7 +248,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {

case 'global.string': {
const arg = walk({node: node.args[0], scope})
return mapConcrete(arg, scope, (node) => {
return mapNode(arg, scope, (node) => {
if (node.type === 'unknown') {
return nullUnion({type: 'string'})
}
Expand All @@ -272,8 +272,8 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {

case 'math.sum': {
const values = walk({node: node.args[0], scope})
// use mapConcrete to get concrete resolved value, it will also handle cases where the value is a union
return mapConcrete(values, scope, (node) => {
// use mapNode to get concrete resolved value, it will also handle cases where the value is a union
return mapNode(values, scope, (node) => {
if (node.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand All @@ -284,7 +284,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
}

// Resolve the concrete type of the array elements
return mapConcrete(node.of, scope, (node) => {
return mapNode(node.of, scope, (node) => {
if (node.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand All @@ -300,8 +300,8 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {

case 'math.avg': {
const values = walk({node: node.args[0], scope})
// use mapConcrete to get concrete resolved value, it will also handle cases where the value is a union
return mapConcrete(values, scope, (node) => {
// use mapNode to get concrete resolved value, it will also handle cases where the value is a union
return mapNode(values, scope, (node) => {
if (node.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand All @@ -311,7 +311,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
return {type: 'null'}
}
// Resolve the concrete type of the array elements
return mapConcrete(node.of, scope, (node) => {
return mapNode(node.of, scope, (node) => {
if (node.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand All @@ -328,8 +328,8 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'math.max':
case 'math.min': {
const values = walk({node: node.args[0], scope})
// use mapConcrete to get concrete resolved value, it will also handle cases where the value is a union
return mapConcrete(values, scope, (node) => {
// use mapNode to get concrete resolved value, it will also handle cases where the value is a union
return mapNode(values, scope, (node) => {
if (node.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand All @@ -340,7 +340,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
}

// Resolve the concrete type of the array elements
return mapConcrete(node.of, scope, (node) => {
return mapNode(node.of, scope, (node) => {
if (node.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand All @@ -366,8 +366,8 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'string.startsWith': {
const strTypeNode = walk({node: node.args[0], scope})
const prefixTypeNode = walk({node: node.args[1], scope})
return mapConcrete(strTypeNode, scope, (strNode) => {
return mapConcrete(prefixTypeNode, scope, (prefixNode) => {
return mapNode(strTypeNode, scope, (strNode) => {
return mapNode(prefixTypeNode, scope, (prefixNode) => {
if (strNode.type === 'unknown' || prefixNode.type === 'unknown') {
return nullUnion({type: 'boolean'})
}
Expand All @@ -383,8 +383,8 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
case 'string.split': {
const strTypeNode = walk({node: node.args[0], scope})
const sepTypeNode = walk({node: node.args[1], scope})
return mapConcrete(strTypeNode, scope, (strNode) => {
return mapConcrete(sepTypeNode, scope, (sepNode) => {
return mapNode(strTypeNode, scope, (strNode) => {
return mapNode(sepTypeNode, scope, (sepNode) => {
if (strNode.type === 'unknown' || sepNode.type === 'unknown') {
return nullUnion({type: 'array', of: {type: 'string'}})
}
Expand All @@ -399,7 +399,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
}
case 'sanity.versionOf': {
const typeNode = walk({node: node.args[0], scope})
return mapConcrete(typeNode, scope, (typeNode) => {
return mapNode(typeNode, scope, (typeNode) => {
if (typeNode.type === 'unknown') {
return nullUnion({type: 'array', of: {type: 'string'}})
}
Expand All @@ -411,7 +411,7 @@ export function handleFuncCallNode(node: FuncCallNode, scope: Scope): TypeNode {
}
case 'sanity.documentsOf': {
const typeNode = walk({node: node.args[0], scope})
return mapConcrete(typeNode, scope, (typeNode) => {
return mapNode(typeNode, scope, (typeNode) => {
if (typeNode.type === 'unknown') {
return nullUnion({type: 'array', of: {type: 'string'}})
}
Expand Down
34 changes: 17 additions & 17 deletions src/typeEvaluator/typeEvaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {handleFuncCallNode} from './functions'
import {match} from './matching'
import {optimizeUnions} from './optimizations'
import {Context, Scope} from './scope'
import {isFuncCall, mapConcrete, nullUnion, resolveInline} from './typeHelpers'
import {isFuncCall, mapNode, nullUnion, resolveInline} from './typeHelpers'
import type {
ArrayTypeNode,
BooleanTypeNode,
Expand Down Expand Up @@ -123,7 +123,7 @@ function handleObjectSplatNode(
): TypeNode {
const value = walk({node: attr.value, scope})
$trace('object.splat.value %O', value)
return mapConcrete(value, scope, (node) => {
return mapNode(value, scope, (node) => {
// splatting over unknown is unknown, we can't know what the attributes are
if (node.type === 'unknown') {
return {type: 'unknown'}
Expand Down Expand Up @@ -258,7 +258,7 @@ function handleObjectNode(node: ObjectNode, scope: Scope): TypeNode {
}
}

const variant = mapConcrete(attributeNode, scope, (attributeNode) => {
const variant = mapNode(attributeNode, scope, (attributeNode) => {
$trace('object.conditional.splat.result.concrete %O', attributeNode)
if (attributeNode.type !== 'object') {
return {type: 'unknown'}
Expand Down Expand Up @@ -462,9 +462,9 @@ function handleOpCallNode(node: OpCallNode, scope: Scope): TypeNode {
$trace('opcall.node %O', node)
const lhs = walk({node: node.left, scope})
const rhs = walk({node: node.right, scope})
return mapConcrete(lhs, scope, (left) =>
return mapNode(lhs, scope, (left) =>
// eslint-disable-next-line complexity, max-statements
mapConcrete(rhs, scope, (right) => {
mapNode(rhs, scope, (right) => {
$trace('opcall.node.concrete "%s" %O', node.op, {left, right})

switch (node.op) {
Expand Down Expand Up @@ -562,7 +562,7 @@ function handleOpCallNode(node: OpCallNode, scope: Scope): TypeNode {
value: false,
} satisfies BooleanTypeNode
}
return mapConcrete(right.of, scope, (arrayTypeNode) => {
return mapNode(right.of, scope, (arrayTypeNode) => {
if (arrayTypeNode.type === 'unknown') {
return nullUnion({type: 'boolean'})
}
Expand Down Expand Up @@ -773,7 +773,7 @@ function handleFlatMap(node: FlatMapNode, scope: Scope): TypeNode {
return mapArray(base, scope, (base) => {
const inner = walk({node: node.expr, scope: scope.createHidden([base.of])})

return mapConcrete(
return mapNode(
inner,
scope,
(inner) => {
Expand Down Expand Up @@ -835,7 +835,7 @@ function handleFilterNode(node: FilterNode, scope: Scope): TypeNode {
const base = walk({node: node.base, scope})
$trace('filter.base %O', base)

return mapConcrete(base, scope, (base) => {
return mapNode(base, scope, (base) => {
$trace('filter.resolving %O', base)
if (base.type === 'null') {
return base
Expand Down Expand Up @@ -988,7 +988,7 @@ function handleParentNode({n}: ParentNode, scope: Scope): TypeNode {

function handleNotNode(node: NotNode, scope: Scope): TypeNode {
const base = walk({node: node.base, scope})
return mapConcrete(base, scope, (base) => {
return mapNode(base, scope, (base) => {
if (base.type === 'unknown') {
return nullUnion({type: 'boolean'})
}
Expand All @@ -1006,7 +1006,7 @@ function handleNotNode(node: NotNode, scope: Scope): TypeNode {

function handleNegNode(node: NegNode, scope: Scope): TypeNode {
const base = walk({node: node.base, scope})
return mapConcrete(base, scope, (base) => {
return mapNode(base, scope, (base) => {
if (base.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand All @@ -1022,7 +1022,7 @@ function handleNegNode(node: NegNode, scope: Scope): TypeNode {
}
function handlePosNode(node: PosNode, scope: Scope): TypeNode {
const base = walk({node: node.base, scope})
return mapConcrete(base, scope, (base) => {
return mapNode(base, scope, (base) => {
if (base.type === 'unknown') {
return nullUnion({type: 'number'})
}
Expand Down Expand Up @@ -1051,8 +1051,8 @@ function handleEverythingNode(_: EverythingNode, scope: Scope): TypeNode {
function handleAndNode(node: AndNode, scope: Scope): TypeNode {
const left = walk({node: node.left, scope})
const right = walk({node: node.right, scope})
return mapConcrete(left, scope, (lhs) =>
mapConcrete(right, scope, (rhs) => {
return mapNode(left, scope, (lhs) =>
mapNode(right, scope, (rhs) => {
const value = booleanAnd(booleanValue(lhs, scope), booleanValue(rhs, scope))

return booleanInterpretationToTypeNode(value)
Expand All @@ -1063,8 +1063,8 @@ function handleAndNode(node: AndNode, scope: Scope): TypeNode {
function handleOrNode(node: OrNode, scope: Scope): TypeNode {
const left = walk({node: node.left, scope})
const right = walk({node: node.right, scope})
return mapConcrete(left, scope, (lhs) =>
mapConcrete(right, scope, (rhs) => {
return mapNode(left, scope, (lhs) =>
mapNode(right, scope, (rhs) => {
const value = booleanOr(booleanValue(lhs, scope), booleanValue(rhs, scope))

return booleanInterpretationToTypeNode(value)
Expand Down Expand Up @@ -1266,7 +1266,7 @@ function mapArray(
scope: Scope,
mapper: (node: ArrayTypeNode) => TypeNode,
): TypeNode {
return mapConcrete(node, scope, (base) => {
return mapNode(node, scope, (base) => {
if (base.type === 'unknown') {
return base
}
Expand All @@ -1282,7 +1282,7 @@ function mapObject(
scope: Scope,
mapper: (node: ObjectTypeNode) => TypeNode,
): TypeNode {
return mapConcrete(node, scope, (base) => {
return mapNode(node, scope, (base) => {
if (base.type === 'unknown') {
return base
}
Expand Down
10 changes: 4 additions & 6 deletions src/typeEvaluator/typeHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,12 @@ export function resolveInline(node: TypeNode, scope: Scope): Exclude<TypeNode, I
}

/**
* mapConcrete extracts a _concrete type_ OR an _unknown type node_ from a type node, applies the mapping
* mapNode extracts either a _concrete type_ OR an _unknown type_ from a type node, applies the mapping
* function to it and returns. Most notably, this will work through unions
* (applying the mapping function for each variant) and inline (resolving the
* reference).
* This method should _only_ be used if you need to handle unknown types, ie when resolving two sides of an and node, and we don't want to abort if one side is unknown.
* In most cases, you should use `mapConcrete` instead.
**/
export function mapConcrete<T extends TypeNode = TypeNode>(
export function mapNode<T extends TypeNode = TypeNode>(
node: TypeNode,
scope: Scope,
mapper: (node: ConcreteTypeNode | UnknownTypeNode) => T,
Expand All @@ -120,10 +118,10 @@ export function mapConcrete<T extends TypeNode = TypeNode>(
case 'unknown':
return mapper(node)
case 'union':
return mergeUnions(node.of.map((inner) => mapConcrete(inner, scope, mapper), mergeUnions))
return mergeUnions(node.of.map((inner) => mapNode(inner, scope, mapper), mergeUnions))
case 'inline': {
const resolvedInline = resolveInline(node, scope)
return mapConcrete(resolvedInline, scope, mapper, mergeUnions)
return mapNode(resolvedInline, scope, mapper, mergeUnions)
}
default:
// @ts-expect-error - all types should be handled
Expand Down

0 comments on commit 494c393

Please sign in to comment.