diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ce4e4c..089da2d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,7 +16,7 @@ importers: version: 5.2.5 dope2: specifier: git+https://deemz.org/git/joeri/dope2.git - version: git+https://deemz.org/git/joeri/dope2.git#70fb80a9fc8438a588d1fba957706a322d0900d0 + version: git+https://deemz.org/git/joeri/dope2.git#d3515d39a51d0baf9fcc775b8d2fb74c74e24868 react: specifier: ^19.1.0 version: 19.1.0 @@ -597,8 +597,8 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dope2@git+https://deemz.org/git/joeri/dope2.git#70fb80a9fc8438a588d1fba957706a322d0900d0: - resolution: {commit: 70fb80a9fc8438a588d1fba957706a322d0900d0, repo: https://deemz.org/git/joeri/dope2.git, type: git} + dope2@git+https://deemz.org/git/joeri/dope2.git#d3515d39a51d0baf9fcc775b8d2fb74c74e24868: + resolution: {commit: d3515d39a51d0baf9fcc775b8d2fb74c74e24868, repo: https://deemz.org/git/joeri/dope2.git, type: git} version: 0.0.1 esbuild@0.25.4: @@ -1431,7 +1431,7 @@ snapshots: deep-is@0.1.4: {} - dope2@git+https://deemz.org/git/joeri/dope2.git#70fb80a9fc8438a588d1fba957706a322d0900d0: + dope2@git+https://deemz.org/git/joeri/dope2.git#d3515d39a51d0baf9fcc775b8d2fb74c74e24868: dependencies: functional-red-black-tree: 1.0.1 diff --git a/src/EnvContext.ts b/src/EnvContext.ts index 9717ae4..f2d100e 100644 --- a/src/EnvContext.ts +++ b/src/EnvContext.ts @@ -1,20 +1,13 @@ import { createContext } from "react"; import { getDefaultTypeParser, module2Env, ModuleStd } from "dope2"; -import type { Dynamic, Environment } from "./eval"; export const functionWith3Params = i => j => k => i+j+k; export const functionWith4Params = i => j => k => l => i+j+k+l; const mkType = getDefaultTypeParser(); - -export const extendedEnv: Environment = { - names: module2Env(ModuleStd.concat([ - ["functionWith3Params", { i: functionWith3Params, t: mkType("Int->Int->Int->Int") }], - ["functionWith4Params", { i: functionWith4Params, t: mkType("Int->Int->Int->Int->Int")}] - ]).map(([name, {i,t}]) => [name, { kind: "value", i, t, unification: new Map() }] as [string, Dynamic]) - ).name2dyn, - nextFreeTypeVar: 0, - typeVars: new Set(), -}; +export const extendedEnv = module2Env(ModuleStd.concat([ + ["functionWith3Params", { i: functionWith3Params, t: mkType("Int->Int->Int->Int") }], + ["functionWith4Params", { i: functionWith4Params, t: mkType("Int->Int->Int->Int->Int")}] +])); export const EnvContext = createContext(extendedEnv); \ No newline at end of file diff --git a/src/InputBlock.tsx b/src/InputBlock.tsx index 1a230e9..3ea0345 100644 --- a/src/InputBlock.tsx +++ b/src/InputBlock.tsx @@ -44,7 +44,7 @@ const computeSuggestions = (text, env, suggestionPriority: (s: ResolvedType) => ... literals.map((lit) => ["literal", text, lit]), // names - ... trie.suggest(env.names)(text)(Infinity) + ... trie.suggest(env.name2dyn)(text)(Infinity) .map(([name,type]) => [ "name", name, { @@ -53,7 +53,8 @@ const computeSuggestions = (text, env, suggestionPriority: (s: ResolvedType) => kind: type.kind || "value", }]), ] - // return []; // <-- uncomment to disable suggestions (useful for debugging) + // return ls; + return []; return ls .map(suggestion => [suggestionPriority(suggestion[2]), ...suggestion] as PrioritizedSuggestionType) .sort(([priorityA], [priorityB]) => priorityB - priorityA) @@ -66,7 +67,7 @@ export function InputBlock({ state, setState, suggestionPriority, onCancel }: In const [i, setI] = useState(0); // selected suggestion idx const [haveFocus, setHaveFocus] = useState(false); // whether to render suggestions or not - const singleSuggestion = trie.growPrefix(env.names)(text); + const singleSuggestion = trie.growPrefix(env.name2dyn)(text); const suggestions = useMemo(() => computeSuggestions(text, env, suggestionPriority), [text, suggestionPriority, env]); useEffect(() => autoInputWidth(inputRef, text+singleSuggestion), [inputRef, text, singleSuggestion]); @@ -88,12 +89,7 @@ export function InputBlock({ state, setState, suggestionPriority, onCancel }: In } const onTextChange = newText => { - setState(state => ({...state, - text: newText, - value: (trie.get(env.names)(newText) ? { - kind: "name", - } : state.value), - })); + setState(state => ({...state, text: newText})); } // fired before onInput diff --git a/src/LambdaBlock.tsx b/src/LambdaBlock.tsx index eb9592a..1db6261 100644 --- a/src/LambdaBlock.tsx +++ b/src/LambdaBlock.tsx @@ -1,14 +1,13 @@ import { useContext, useEffect, useRef } from "react"; -import { eqType, getSymbol, reduceUnification, trie } from "dope2"; +import { growEnv } from "dope2"; import { ExprBlock, type ExprBlockState, type State2Props } from "./ExprBlock"; import { EnvContext } from "./EnvContext"; -import { evalEditorBlock, makeInnerEnv, makeTypeVar } from "./eval"; +import { getUnusedTypeVar } from "./eval"; import { autoInputWidth } from "./util/dom_trickery"; import "./LambdaBlock.css"; -import { Type } from "./Type"; export interface LambdaBlockState { kind: "lambda"; @@ -48,20 +47,11 @@ export function LambdaBlock({state, setState, suggestionPriority}: LambdaBlockPr useEffect(() => autoInputWidth(nameRef, state.paramName, 60), [nameRef, state.paramName]); - const [paramType, staticInnerEnv] = makeTypeVar(env, state.paramName); - - const exprResolved = evalEditorBlock(state.expr, staticInnerEnv); - - const inferredParamType = reduceUnification(exprResolved.unification).get(getSymbol(paramType)) || paramType; - - const betterInnerEnv = eqType(paramType)(inferredParamType) - ? staticInnerEnv - : makeInnerEnv(env, state.paramName, { - kind: "unknown", - t: inferredParamType, - unification: new Map(), // <- is this correct? - }) - + const innerEnv = growEnv(env)(state.paramName)({ + kind: "unknown", + i: undefined, + t: getUnusedTypeVar(env), + }); return λ @@ -76,14 +66,11 @@ export function LambdaBlock({state, setState, suggestionPriority}: LambdaBlockPr onChange={e => setParamName(e.target.value)} /> -
-  ::  -
  :  
- + default: - console.log("don't know how to show value:", dynamic); return <>don't know how to show value; } } diff --git a/src/configurations.ts b/src/configurations.ts index 05bff68..0ec9113 100644 --- a/src/configurations.ts +++ b/src/configurations.ts @@ -75,7 +75,184 @@ export const tripleFunctionCallEditorState: ExprBlockState = { }, }; -export const biggerExample: ExprBlockState = {"kind":"let","inner":{"kind":"let","inner":{"kind":"let","inner":{"kind":"let","inner":{"kind":"input","text":"","value":{"kind":"text"},"focus":false},"name":"myListInc","value":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"list.map","value":{"kind":"name"},"focus":false},"input":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"list.map","value":{"kind":"name"},"focus":false},"input":{"kind":"input","text":"myList","value":{"kind":"name"},"focus":false}},"input":{"kind":"input","text":"inc","value":{"kind":"name"},"focus":false}}},"input":{"kind":"input","text":"id","value":{"kind":"name"},"focus":true}}},"name":"myList","value":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"list.push","value":{"kind":"name"},"focus":false},"input":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"list.push","value":{"kind":"name"},"focus":false},"input":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"list.push","value":{"kind":"name"},"focus":false},"input":{"kind":"input","text":"list.emptyList","value":{"kind":"name"},"focus":false}},"input":{"kind":"input","text":"1","value":{"kind":"literal","type":"Int"},"focus":false}}},"input":{"kind":"input","text":"2","value":{"kind":"literal","type":"Int"},"focus":false}}},"input":{"kind":"input","text":"3","value":{"kind":"literal","type":"Int"},"focus":false}}},"name":"id","value":{"kind":"lambda","paramName":"x","expr":{"kind":"input","text":"x","value":{"kind":"name"},"focus":false}}},"name":"inc","value":{"kind":"lambda","paramName":"x","expr":{"kind":"call","fn":{"kind":"call","fn":{"kind":"input","text":"addInt","value":{"kind":"name"},"focus":false},"input":{"kind":"input","text":"x","value":{"kind":"name"},"focus":false}},"input":{"kind":"input","text":"1","value":{"kind":"literal","type":"Int"},"focus":true}}}}; +export const biggerExample: ExprBlockState = { + "kind": "let", + "inner": { + "kind": "let", + "inner": { + "kind": "let", + "inner": { + "kind": "let", + "inner": { + "kind": "input", + "text": "", + "value": { + "kind": "text" + }, + "focus": false + }, + "name": "myListInc", + "value": { + "kind": "call", + "fn": { + "kind": "call", + "fn": { + "kind": "input", + "text": "list.map", + "value": { + "kind": "name" + }, + "focus": false + }, + "input": { + "kind": "input", + "text": "myList", + "value": { + "kind": "name" + }, + "focus": false + } + }, + "input": { + "kind": "input", + "text": "inc", + "value": { + "kind": "name" + }, + "focus": false + } + } + }, + "name": "myList", + "value": { + "kind": "call", + "fn": { + "kind": "call", + "fn": { + "kind": "input", + "text": "list.push", + "value": { + "kind": "name" + }, + "focus": false + }, + "input": { + "kind": "call", + "fn": { + "kind": "call", + "fn": { + "kind": "input", + "text": "list.push", + "value": { + "kind": "name" + }, + "focus": false + }, + "input": { + "kind": "call", + "fn": { + "kind": "call", + "fn": { + "kind": "input", + "text": "list.push", + "value": { + "kind": "name" + }, + "focus": false + }, + "input": { + "kind": "input", + "text": "list.emptyList", + "value": { + "kind": "name" + }, + "focus": false + } + }, + "input": { + "kind": "input", + "text": "1", + "value": { + "kind": "literal", + "type": "Int" + }, + "focus": false + } + } + }, + "input": { + "kind": "input", + "text": "2", + "value": { + "kind": "literal", + "type": "Int" + }, + "focus": false + } + } + }, + "input": { + "kind": "input", + "text": "3", + "value": { + "kind": "literal", + "type": "Int" + }, + "focus": false + } + } + }, + "name": "id", + "value": { + "kind": "lambda", + "paramName": "x", + "expr": { + "kind": "input", + "text": "x", + "value": { + "kind": "name" + }, + "focus": false + } + } + }, + "name": "inc", + "value": { + "kind": "lambda", + "paramName": "x", + "expr": { + "kind": "call", + "fn": { + "kind": "call", + "fn": { + "kind": "input", + "text": "addInt", + "value": { + "kind": "name" + }, + "focus": false + }, + "input": { + "kind": "input", + "text": "x", + "value": { + "kind": "name" + }, + "focus": false + } + }, + "input": { + "kind": "input", + "text": "1", + "value": { + "kind": "literal", + "type": "Int" + }, + "focus": true + } + } + } +}; export const lambda2Params: ExprBlockState = { "kind": "let", diff --git a/src/eval.ts b/src/eval.ts index c1af9f4..d756806 100644 --- a/src/eval.ts +++ b/src/eval.ts @@ -1,29 +1,19 @@ -import { Double, fnType, getHumanReadableName, getSymbol, Int, mergeUnifications, NotAFunctionError, occurring, prettyT, prettyU, recomputeTypeVars, reduceUnification, substitute, symbolFunction, trie, TYPE_VARS, UNBOUND_SYMBOLS, UnifyError, unifyLL, transitivelyGrow } from "dope2"; +import { assignFnSubstitutions, dict, Double, fnType, getSymbol, growEnv, Int, NotAFunctionError, prettyT, substitute, symbolFunction, trie, TYPE_VARS, UnifyError } from "dope2"; import type { ExprBlockState } from "./ExprBlock"; -import type { InputValueType } from "./InputBlock"; - -const IS_DEV = (import.meta.env.MODE === "development"); - -export interface Environment { - names: any; - nextFreeTypeVar: number; - typeVars: Set; -} +import type { InputValueType, SuggestionType } from "./InputBlock"; interface Type { symbol: string; params: any[]; }; -type Unification = Map; - export interface DeepError { kind: "error"; e: Error; depth: number; t: Type; - unification: Unification; + substitutions: Map; } // a dynamically typed value = tuple (instance, type) @@ -31,15 +21,21 @@ export interface Dynamic { kind: "value", i: any; t: Type; - unification: Unification; + substitutions: Map; }; export interface Unknown { kind: "unknown"; t: Type; - unification: Unification; + substitutions: Map; } +export const entirelyUnknown = env => ({ + kind: "unknown", + t: getUnusedTypeVar(env), + substitutions: new Map(), +} as Unknown); + // the value of every block is either known (Dynamic), an error, or unknown export type ResolvedType = Dynamic | DeepError | Unknown; @@ -47,15 +43,17 @@ export const evalEditorBlock = (s: ExprBlockState, env): ResolvedType => { if (s.kind === "input") { return evalInputBlock(s.text, s.value, env); } - else if (s.kind === "call") { + if (s.kind === "call") { return evalCallBlock(s.fn, s.input, env); } - else if (s.kind === "let") { + if (s.kind === "let") { return evalLetInBlock(s.value, s.name, s.inner, env); } - else { // (s.kind === "lambda") + if (s.kind === "lambda") { return evalLambdaBlock(s.paramName, s.expr, env); + } + return entirelyUnknown(env); // todo }; export function evalInputBlock(text: string, value: InputValueType, env): ResolvedType { @@ -63,65 +61,56 @@ export function evalInputBlock(text: string, value: InputValueType, env): Resolv return parseLiteral(text, value.type, env); } else if (value.kind === "name") { - const found = trie.get(env.names)(text); + const found = trie.get(env.name2dyn)(text); if (found) { - return found; + return { + kind: found.kind || "value", + ...found, + substitutions: found.substitutions || new Map(), + }; } } // kind === "text" -> unresolved return { kind: "error", - t: makeTypeVar(env, 'err')[0], + t: getUnusedTypeVar(env), e: new Error(`'${text}' not found`), depth: 0, - unification: new Map(), + substitutions: new Map(), }; } +const mergeMaps = (...maps: Map[]) => { + return new Map(maps.flatMap(m => [...m])); +} export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: ResolvedType, env): ResolvedType { if (getSymbol(fnResolved.t) !== symbolFunction) { // worst outcome: we know nothing about the result! - return makeError(env, - new NotAFunctionError(`${prettyT(fnResolved.t)} is not a function type!`), - mergeUnifications(fnResolved.unification, inputResolved.unification), - ) + return { + kind: "error", + e: new NotAFunctionError(`${prettyT(fnResolved.t)} is not a function type!`), + t: getUnusedTypeVar(env), + substitutions: mergeMaps(fnResolved.substitutions, inputResolved.substitutions), + depth: 0, + }; } try { // fn is a function... - const [rewrittenFnType] = recomputeTypeVars([fnResolved.t], env.nextFreeTypeVar); - const unification = (unifyLL(rewrittenFnType.params[0](rewrittenFnType), inputResolved.t)); + const [_inType, inSubst, outType, _outSubst] = assignFnSubstitutions(fnResolved.t, inputResolved.t, getUnusedTypeVarIdx(env)); // may throw - const inputTypeVars = occurring(inputResolved.t); - const fnTypeVars = occurring(fnResolved.t); - const subsetOfUnification = new Map([...unification].filter(([typeVar]) => inputTypeVars.has(typeVar))); - const otherSubSetOfUnification = new Map([...unification].filter(([typeVar]) => fnTypeVars.has(typeVar))); - - const outType = substitute( - rewrittenFnType.params[1](rewrittenFnType), - reduceUnification(unification), - []); // <- not important - - const grandUnification = [fnResolved.unification, inputResolved.unification] - .reduce(mergeUnifications, unification); - - if (IS_DEV) { - console.log('========= evalCallBlock2 =========') - console.log('fnType :', prettyT(fnResolved.t)); - console.log('rewrittenFnType :', prettyT(rewrittenFnType)); - console.log('inputType :', prettyT(inputResolved.t)); - console.log('unification :', prettyU(unification)); - console.log('subsetOfUnification :', prettyU(subsetOfUnification)); - console.log('otherSubSetOfUnification:', prettyU(otherSubSetOfUnification)); - console.log('outType :', prettyT(outType)); - // console.log('inputTypeVars :', `{${[...inputTypeVars].map(getHumanReadableName).join(', ')}}`); - // console.log('fnTypeVars :', `{${[...fnTypeVars].map(getHumanReadableName).join(', ')}}`); - console.log('fn.unification :', prettyU(fnResolved.unification)); - console.log('input.unification :', prettyU(inputResolved.unification)); - console.log('grandUnification :', prettyU(grandUnification)); - console.log('==================================') - } + console.log('==================================') + console.log('fnResolvedT:', prettyT(fnResolved.t)); + console.log('inputResolvedT:', prettyT(inputResolved.t)); + console.log('_inType:',prettyT(_inType)); + console.log('inSubst:', [...inSubst].map(([key,val]) => [key,prettyT(val)])); + console.log('outType:',prettyT(outType)); + console.log('_outSubst:', [..._outSubst].map(([key,val]) => [key,prettyT(val)])); + console.log('==================================') + // console.log('assignFn...', 'fn.t:', prettyT(fnResolved.t), 'input:', inputResolved, 'input.t:', prettyT(inputResolved.t), '\nout =', prettyT(outType), 'subst:', substitutions, substitutions.size); + + const mergedSubstitutions = mergeMaps(inSubst, fnResolved.substitutions, inputResolved.substitutions); if (inputResolved.kind === "error") { return { @@ -129,7 +118,7 @@ export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: Resolved e: inputResolved.e, // bubble up the error depth: 0, t: outType, - unification: grandUnification, + substitutions: mergedSubstitutions, }; } if (fnResolved.kind === "error") { @@ -139,7 +128,7 @@ export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: Resolved e: fnResolved.e, depth: fnResolved.depth+1, t: outType, - unification: grandUnification, + substitutions: mergedSubstitutions, }; } // if the above statement did not throw => types are compatible... @@ -149,7 +138,7 @@ export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: Resolved kind: "value", i: outValue, t: outType, - unification: grandUnification, + substitutions: mergedSubstitutions, }; } else { @@ -157,7 +146,7 @@ export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: Resolved return { kind: "unknown", t: outType, - unification: grandUnification, + substitutions: mergedSubstitutions, }; } } @@ -165,25 +154,17 @@ export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: Resolved if ((e instanceof UnifyError)) { // even though fn was incompatible with the given parameter, we can still suppose that our output-type will be that of fn...? const outType = fnResolved.t.params[1](fnResolved.t); - try { - return { - kind: "error", - e, - depth: 0, - t: outType, - unification: mergeUnifications(fnResolved.unification, inputResolved.unification), // may throw! - }; - } - catch (e) { - if ((e instanceof UnifyError)) { - return makeError(env, e); - } - throw e; - } + return { + kind: "error", + e, + depth: 0, + t: outType, + substitutions: mergeMaps(fnResolved.substitutions, inputResolved.substitutions), + }; } throw e; } -}; +} export function evalCallBlock(fn: ExprBlockState, input: ExprBlockState, env): ResolvedType { const fnResolved = evalEditorBlock(fn, env); @@ -193,30 +174,35 @@ export function evalCallBlock(fn: ExprBlockState, input: ExprBlockState, env): R export function evalLetInBlock(value: ExprBlockState, name: string, inner: ExprBlockState, env): ResolvedType { const valueResolved = evalEditorBlock(value, env); + // console.log('eval', name, '...', valueResolved.kind, valueResolved.e); + // const innerEnv = growEnv(env)(name)(valueResolved); const innerEnv = makeInnerEnv(env, name, valueResolved); return evalEditorBlock(inner, innerEnv); } +function getUnusedTypeVarIdx(env) { + for (let i=0; ; i++) { + if (!dict.has(env.typeDict)(TYPE_VARS[i])) { + return i; + } + } +} + +export function getUnusedTypeVar(env) { + return TYPE_VARS[getUnusedTypeVarIdx(env)]; +} export function evalLambdaBlock(paramName: string, expr: ExprBlockState, env): ResolvedType { - const [paramType, staticInnerEnv] = makeTypeVar(env, paramName); + const paramType = getUnusedTypeVar(env); + // static env: we only know the name and the type + const staticInnerEnv = growEnv(env)(paramName)({ + kind: "unknown", // parameter value is not statically known + t: paramType, + substitutions: new Map(), + }) const exprResolved = evalEditorBlock(expr, staticInnerEnv); const lambdaT = fnType(_ => paramType)(_ => exprResolved.t); - // This is the only place in the code where we actually do something with the 'substitutions'. We compute the type of our lambda function: - const lambdaTSubstituted = substitute( - lambdaT, - reduceUnification(exprResolved.unification), - []); // <- not important - - if (IS_DEV) { - console.log('========= evalLambdaBlock =========') - console.log('paramType :', prettyT(paramType)); - console.log('exprType :', prettyT(exprResolved.t)); - console.log('lambdaType :', prettyT(lambdaT)); - console.log('lambdaTypeSubsituted:', prettyT(lambdaTSubstituted)); - console.log('===================================') - } - + const lambdaTSubstituted = substitute(lambdaT, exprResolved.substitutions, []); // console.log('inner kind', exprResolved.kind, paramName); if (exprResolved.kind === "error") { return { @@ -224,7 +210,8 @@ export function evalLambdaBlock(paramName: string, expr: ExprBlockState, env): R t: lambdaTSubstituted, depth: 0, e: exprResolved.e, - unification: exprResolved.unification, + // substitutions: new Map(), + substitutions: exprResolved.substitutions, } } const paramTypeSubstituted = lambdaTSubstituted.params[0](lambdaTSubstituted); @@ -233,7 +220,7 @@ export function evalLambdaBlock(paramName: string, expr: ExprBlockState, env): R kind: "value", i: x, t: paramTypeSubstituted, - unification: new Map(), + substitutions: new Map(), }); const result = evalEditorBlock(expr, innerEnv); if (result.kind === "value") { @@ -244,7 +231,7 @@ export function evalLambdaBlock(paramName: string, expr: ExprBlockState, env): R kind: "value", t: lambdaTSubstituted, i: fn, - unification: exprResolved.unification, + substitutions: exprResolved.substitutions, }; } @@ -261,7 +248,7 @@ function parseLiteral(text: string, type: string, env): ResolvedType { if (type === "Double") { return parseAsDouble(text, env); } - return makeError(env, new Error("Failed to parse")); + return entirelyUnknown(env); } function parseAsDouble(text: string, env): ResolvedType { @@ -272,11 +259,11 @@ function parseAsDouble(text: string, env): ResolvedType { kind: "value", i: num, t: Double, - unification: new Map(), + substitutions: new Map(), }; } } - return makeError(env, new Error("Failed to parse as Double")); + return entirelyUnknown(env); } function parseAsInt(text: string, env): ResolvedType { if (text !== '') { @@ -285,12 +272,12 @@ function parseAsInt(text: string, env): ResolvedType { kind: "value", i: BigInt(text), t: Int, - unification: new Map(), + substitutions: new Map(), }; // may throw } catch {} } - return makeError(env, new Error("Failed to parse as Int")); + return entirelyUnknown(env); } const literalParsers = [parseAsDouble, parseAsInt]; @@ -317,45 +304,10 @@ export function scoreResolved(resolved: ResolvedType, outPriority: (s:ResolvedTy } } -export function makeInnerEnv(env: Environment, name: string, value: ResolvedType): Environment { - if (name !== "") { - return { - names: trie.insert(env.names)(name)(value), - nextFreeTypeVar: env.nextFreeTypeVar, - typeVars: env.typeVars, - } +export function makeInnerEnv(env, name: string, value: ResolvedType) { + if (name !== "" && value.kind === "value") { + return growEnv(env)(name)(value); } return env; } -export function makeTypeVar(env: Environment, name: string): [Type, Environment] { - const idx = env.nextFreeTypeVar; - const typeVar = TYPE_VARS[idx]; - const unknown: Unknown = { - kind: "unknown", - t: typeVar, - unification: new Map(), - }; - return [ typeVar, { - names: trie.insert(env.names)(name)(unknown), - nextFreeTypeVar: idx + 1, - typeVars: new Set([...env.typeVars, UNBOUND_SYMBOLS[idx]]), - }]; -} - -function makeError(env: Environment, e: Error, unification: Unification=new Map()): DeepError { - const idx = env.nextFreeTypeVar; - const typeVar = TYPE_VARS[idx]; - const deepError: DeepError = { - kind: "error", - t: typeVar, - unification: new Map(), - e, - depth: 0, - }; - return deepError; - // , { - // names: trie.insert(env.names)('err')(deepError), - // nextFreeTypeVar: idx + 1, - // }]; -} \ No newline at end of file