Compare commits
No commits in common. "428e8cd29815e6fd9a2beb12e6aa84d69a4a58de" and "4a4cee6ee9e471fd7fec07372bd0bcc8f869eb7c" have entirely different histories.
428e8cd298
...
4a4cee6ee9
11 changed files with 70 additions and 107 deletions
|
|
@ -9,7 +9,7 @@ import { biggerExample, emptySet, factorial, higherOrder, higherOrder2Params, in
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import { evalExpr } from '../../eval/eval';
|
import { evalExpr } from '../../eval/eval';
|
||||||
import { Value } from '../other/Value';
|
import { Value } from '../other/Value';
|
||||||
import { Type, TypeInfoBlock } from '../other/Type';
|
import { Type } from '../other/Type';
|
||||||
|
|
||||||
|
|
||||||
const examples: [string, ExprBlockState][] = [
|
const examples: [string, ExprBlockState][] = [
|
||||||
|
|
@ -190,7 +190,7 @@ export function App() {
|
||||||
t: typeInfo.type,
|
t: typeInfo.type,
|
||||||
}}/>
|
}}/>
|
||||||
::
|
::
|
||||||
<TypeInfoBlock typeInfo={typeInfo}/>
|
<Type type={typeInfo.type}/>
|
||||||
</GlobalContext>
|
</GlobalContext>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ export const tripleFunctionCallEditorState: ExprBlockState = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const biggerExample: ExprBlockState = {"kind":"let","focus":false,"inner":{"kind":"let","focus":false,"inner":{"kind":"let","focus":false,"inner":{"kind":"let","focus":false,"inner":{"kind":"input","text":"myList","value":{"kind":"name"}},"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"}}},"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","focus":false,"paramName":"x","expr":{"kind":"input","text":"x","value":{"kind":"name"},"focus":false}}},"name":"inc","value":{"kind":"lambda","focus":false,"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","focus":false,"inner":{"kind":"let","focus":false,"inner":{"kind":"let","focus":false,"inner":{"kind":"let","focus":false,"inner":{"kind":"input","text":"","value":{"kind":"gibberish"},"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","focus":false,"paramName":"x","expr":{"kind":"input","text":"x","value":{"kind":"name"},"focus":false}}},"name":"inc","value":{"kind":"lambda","focus":false,"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 = {
|
export const lambda2Params: ExprBlockState = {
|
||||||
"kind": "let",
|
"kind": "let",
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { EnvContext } from "../../context/EnvContext";
|
||||||
import { GlobalContext } from "../../context/GlobalContext";
|
import { GlobalContext } from "../../context/GlobalContext";
|
||||||
import { type StaticEnvironment, type TypeInfoCall } from "../../eval/infer_type";
|
import { type StaticEnvironment, type TypeInfoCall } from "../../eval/infer_type";
|
||||||
import { getActions } from "../app/actions";
|
import { getActions } from "../app/actions";
|
||||||
import { Type, TypeInfoBlock } from "../other/Type";
|
import { Type } from "../other/Type";
|
||||||
import "./CallBlock.css";
|
import "./CallBlock.css";
|
||||||
import { ExprBlock, type ExprBlockState, type SetStateFn, type State2Props } from "./ExprBlock";
|
import { ExprBlock, type ExprBlockState, type SetStateFn, type State2Props } from "./ExprBlock";
|
||||||
|
|
||||||
|
|
@ -67,7 +67,7 @@ export function CallBlock(props: CallBlockProps) {
|
||||||
{/* { (resolved.kind === "error") && resolved.e.toString()
|
{/* { (resolved.kind === "error") && resolved.e.toString()
|
||||||
|| (resolved.kind === "value") && <Value dynamic={resolved} />
|
|| (resolved.kind === "value") && <Value dynamic={resolved} />
|
||||||
|| "unknown" } */}
|
|| "unknown" } */}
|
||||||
:: <TypeInfoBlock typeInfo={props.typeInfo} />
|
:: <Type type={props.typeInfo.type} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CallContext>
|
</CallContext>
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,10 @@
|
||||||
.editor {
|
.editor {
|
||||||
padding: 2px;
|
padding: 2px;;
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
.editor.error {
|
.editor.error {
|
||||||
border: 1px solid red;
|
border: 1px solid red;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.errorMessage {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
color: darkred;
|
|
||||||
background-color: pink;
|
|
||||||
margin-top: 4px;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor:hover > .errorMessage {
|
|
||||||
display: block;
|
|
||||||
/* z-index: 9999; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor.unknown {
|
.editor.unknown {
|
||||||
border: 1px dashed dodgerblue;
|
border: 1px dashed dodgerblue;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
@ -35,6 +19,37 @@
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.typeSignature {
|
||||||
|
display: inline-block;
|
||||||
|
/* z-index: 1; */
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typeSignature.gotDebug {
|
||||||
|
background-color: gold;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typeDebug {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.typeSignature:hover > .typeDebug {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
white-space-collapse: preserve;
|
||||||
|
width: max-content;
|
||||||
|
background-color: #d2ebf1e0;
|
||||||
|
color: black;
|
||||||
|
font-family: var(--my-monospace-font);
|
||||||
|
padding: 4px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor:hover > .typeSignature {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
.keyword {
|
.keyword {
|
||||||
color: blue;
|
color: blue;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|
|
||||||
|
|
@ -51,13 +51,12 @@ export function ExprBlock(props: ExprBlockProps) {
|
||||||
const extraHandlers = Object.fromEntries(Object.entries(actions).map(([shortcut, action]) =>
|
const extraHandlers = Object.fromEntries(Object.entries(actions).map(([shortcut, action]) =>
|
||||||
[shortcut, (e) => { e.preventDefault(); action(); }]))
|
[shortcut, (e) => { e.preventDefault(); action(); }]))
|
||||||
|
|
||||||
console.log(props.typeInfo.err);
|
|
||||||
return <span className={"editor" + (props.typeInfo.err ? " error" : "")}>
|
return <span className={"editor" + (props.typeInfo.err ? " error" : "")}>
|
||||||
{renderBlock[props.state.kind]()}
|
{renderBlock[props.state.kind]()}
|
||||||
{(props.typeInfo.err !== undefined) &&
|
{props.typeInfo.err &&
|
||||||
(<div className="errorMessage">
|
<div>
|
||||||
{props.typeInfo.err.message}
|
{props.typeInfo.err.message.split('\n')[1]}
|
||||||
</div>)}
|
</div>}
|
||||||
<Input
|
<Input
|
||||||
placeholder="<c>"
|
placeholder="<c>"
|
||||||
text=""
|
text=""
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import { GlobalContext } from "../../context/GlobalContext";
|
||||||
import { inferTypeInput, type StaticEnvironment, type Type, type TypeInfoInput } from "../../eval/infer_type";
|
import { inferTypeInput, type StaticEnvironment, type Type, type TypeInfoInput } from "../../eval/infer_type";
|
||||||
import { getActions } from "../app/actions";
|
import { getActions } from "../app/actions";
|
||||||
import { Input } from "../other/Input";
|
import { Input } from "../other/Input";
|
||||||
import { Type as TypeBlock, TypeInfoBlock } from "../other/Type";
|
import { Type as TypeBlock } from "../other/Type";
|
||||||
import type { ExprBlockState, State2Props } from "./ExprBlock";
|
import type { ExprBlockState, State2Props } from "./ExprBlock";
|
||||||
|
|
||||||
import "./InputBlock.css";
|
import "./InputBlock.css";
|
||||||
|
|
@ -161,7 +161,7 @@ export function InputBlock({ state, setState, score, onCancel, typeInfo }: Input
|
||||||
i={i} setI={setI} />
|
i={i} setI={setI} />
|
||||||
</span>
|
</span>
|
||||||
</Input>
|
</Input>
|
||||||
::<TypeInfoBlock typeInfo={typeInfo} />
|
::<TypeBlock type={typeInfo.type} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,7 +200,7 @@ function Suggestion({ setI, j, onSelect, highlighted, suggestion: [priority, typ
|
||||||
onMouseEnter={onMouseEnter(j)}
|
onMouseEnter={onMouseEnter(j)}
|
||||||
onMouseDown={onMouseDown(j)}>
|
onMouseDown={onMouseDown(j)}>
|
||||||
({priority}) ({kind}) {text} :: <TypeBlock type={type} />
|
({priority}) ({kind}) {text} :: <TypeBlock type={type} />
|
||||||
</div>;
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
const SuggestionMemo = memo<SuggestionProps>(Suggestion);
|
const SuggestionMemo = memo<SuggestionProps>(Suggestion);
|
||||||
|
|
@ -4,7 +4,7 @@ import { EnvContext } from "../../context/EnvContext";
|
||||||
import { GlobalContext } from "../../context/GlobalContext";
|
import { GlobalContext } from "../../context/GlobalContext";
|
||||||
import { type TypeInfoLet } from "../../eval/infer_type";
|
import { type TypeInfoLet } from "../../eval/infer_type";
|
||||||
import { Input } from "../other/Input";
|
import { Input } from "../other/Input";
|
||||||
import { Type, TypeInfoBlock } from "../other/Type";
|
import { Type } from "../other/Type";
|
||||||
import { ExprBlock, type ExprBlockState, type State2Props } from "./ExprBlock";
|
import { ExprBlock, type ExprBlockState, type State2Props } from "./ExprBlock";
|
||||||
|
|
||||||
import "./LetInBlock.css";
|
import "./LetInBlock.css";
|
||||||
|
|
@ -50,7 +50,7 @@ function DeclColumns({state, setState, score, typeInfo}) {
|
||||||
onTextChange={name => setState(state => ({...state, name}))}
|
onTextChange={name => setState(state => ({...state, name}))}
|
||||||
extraHandlers={{}}
|
extraHandlers={{}}
|
||||||
/>
|
/>
|
||||||
:: <TypeInfoBlock typeInfo={typeInfo.value} />
|
:: <Type type={typeInfo.value.type} />
|
||||||
</span>
|
</span>
|
||||||
<span className="keyword column"> = </span>
|
<span className="keyword column"> = </span>
|
||||||
<span className="column">
|
<span className="column">
|
||||||
|
|
|
||||||
|
|
@ -70,29 +70,3 @@
|
||||||
50% { opacity:0; }
|
50% { opacity:0; }
|
||||||
100% { opacity:1; }
|
100% { opacity:1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.typeSignature {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.typeDebug {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.typeSignature:hover > .typeDebug {
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
white-space-collapse: preserve;
|
|
||||||
width: max-content;
|
|
||||||
background-color: #d2ebf1e0;
|
|
||||||
color: black;
|
|
||||||
font-family: var(--my-monospace-font);
|
|
||||||
padding: 4px;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.editor:hover > .typeSignature {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,7 @@
|
||||||
import { getHumanReadableName, getSymbol, prettySS, symbolDict, symbolDictIterator, symbolFunction, symbolList, symbolProduct, symbolSet, symbolSetIterator, symbolSum } from "dope2";
|
import { getHumanReadableName, getSymbol, symbolDict, symbolDictIterator, symbolFunction, symbolList, symbolProduct, symbolSet, symbolSetIterator, symbolSum } from "dope2";
|
||||||
|
|
||||||
import "./Type.css";
|
import "./Type.css";
|
||||||
import { ValueUnknown } from "./Value";
|
import { ValueUnknown } from "./Value";
|
||||||
import type { TypeInfo } from "../../eval/infer_type";
|
|
||||||
|
|
||||||
export function TypeInfoBlock({typeInfo}: {typeInfo: TypeInfo}) {
|
|
||||||
return <span className="typeSignature gotDebug">
|
|
||||||
<Type type={typeInfo.type}/>
|
|
||||||
<br/>
|
|
||||||
<span className="typeDebug">{prettySS(typeInfo.subs)}</span>
|
|
||||||
</span>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Type({type}) {
|
export function Type({type}) {
|
||||||
if (type === undefined) {
|
if (type === undefined) {
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ export function evalLet(s: LetInBlockState, env: DynamicEnvironment): EvalResult
|
||||||
const valueEnv = {
|
const valueEnv = {
|
||||||
names: trie.insert(env.names)(s.name)({
|
names: trie.insert(env.names)(s.name)({
|
||||||
recursive: true,
|
recursive: true,
|
||||||
i: () => { try { return value; } catch (e) {} },
|
i: () => value,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
const value = evalExpr(s.value, valueEnv);
|
const value = evalExpr(s.value, valueEnv);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Double, eqType, fnType, getHumanReadableName, IncompatibleTypesError, Int, mergeSubstitutionsN, occurring, prettySS, prettyT, recomputeTypeVars, substitute, SubstitutionCycle, trie, TYPE_VARS, UNBOUND_SYMBOLS, unify } from "dope2";
|
import { Double, eqType, fnType, IncompatibleTypesError, Int, mergeSubstitutionsN, occurring, recomputeTypeVars, substitute, SubstitutionCycle, trie, TYPE_VARS, UNBOUND_SYMBOLS, unify } from "dope2";
|
||||||
|
|
||||||
import type { CallBlockState } from "../component/expr/CallBlock";
|
import type { CallBlockState } from "../component/expr/CallBlock";
|
||||||
import type { ExprBlockState } from "../component/expr/ExprBlock";
|
import type { ExprBlockState } from "../component/expr/ExprBlock";
|
||||||
|
|
@ -8,8 +8,8 @@ import type { LetInBlockState } from "../component/expr/LetInBlock";
|
||||||
import { memoize } from "../util/memoize";
|
import { memoize } from "../util/memoize";
|
||||||
|
|
||||||
export interface StaticEnvironment {
|
export interface StaticEnvironment {
|
||||||
names: any; // mapping from name to type
|
names: any;
|
||||||
typevars: Set<string>; // set of type variables currently in use
|
typevars: Set<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Type {
|
export interface Type {
|
||||||
|
|
@ -98,7 +98,7 @@ export const inferTypeInput = memoize(function inferTypeInput(s: InputBlockState
|
||||||
type,
|
type,
|
||||||
subs: new Map(),
|
subs: new Map(),
|
||||||
newEnv,
|
newEnv,
|
||||||
err: new Error(`'${s.text}' not found`),
|
err: new Error("Gibberish"),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -163,15 +163,10 @@ export const inferTypeCall = memoize(function inferTypeCall(s: CallBlockState, e
|
||||||
});
|
});
|
||||||
|
|
||||||
export const inferTypeLet = memoize(function inferTypeLet(s: LetInBlockState, env: StaticEnvironment): TypeInfoLet {
|
export const inferTypeLet = memoize(function inferTypeLet(s: LetInBlockState, env: StaticEnvironment): TypeInfoLet {
|
||||||
console.log('inferTypeLet..', env.typevars);
|
const recursiveTypeInfo = iterateRecursiveType(s.name, s.value, env);
|
||||||
const recursiveTypeInfo = iterateRecursiveType(s.name, s.value, env, true);
|
|
||||||
console.log('end inferTypeLet.');
|
|
||||||
console.log({recursiveTypeInfo});
|
|
||||||
// to eval the 'inner' expr, we only need to add our parameter to the environment:
|
// to eval the 'inner' expr, we only need to add our parameter to the environment:
|
||||||
const innerEnv = {
|
const innerEnv = {
|
||||||
names: trie.insert(env.names)(s.name)({
|
names: trie.insert(env.names)(s.name)({kind: "value", t: recursiveTypeInfo.paramType}),
|
||||||
t: recursiveTypeInfo.inner.type,
|
|
||||||
}),
|
|
||||||
typevars: env.typevars,
|
typevars: env.typevars,
|
||||||
};
|
};
|
||||||
const innerTypeInfo = inferType(s.inner, innerEnv);
|
const innerTypeInfo = inferType(s.inner, innerEnv);
|
||||||
|
|
@ -187,9 +182,7 @@ export const inferTypeLet = memoize(function inferTypeLet(s: LetInBlockState, en
|
||||||
});
|
});
|
||||||
|
|
||||||
export const inferTypeLambda = memoize(function inferTypeLambda(s: LambdaBlockState, env: StaticEnvironment): TypeInfoLambda {
|
export const inferTypeLambda = memoize(function inferTypeLambda(s: LambdaBlockState, env: StaticEnvironment): TypeInfoLambda {
|
||||||
console.log('inferTypeLambda..', env.typevars);
|
const recursiveTypeInfo = iterateRecursiveType(s.paramName, s.expr, env);
|
||||||
const recursiveTypeInfo = iterateRecursiveType(s.paramName, s.expr, env, false);
|
|
||||||
console.log('end inferTypeLambda.');
|
|
||||||
return {
|
return {
|
||||||
kind: "lambda",
|
kind: "lambda",
|
||||||
type: fnType(_ => recursiveTypeInfo.paramType)(_ => recursiveTypeInfo.inner.type),
|
type: fnType(_ => recursiveTypeInfo.paramType)(_ => recursiveTypeInfo.inner.type),
|
||||||
|
|
@ -199,36 +192,21 @@ export const inferTypeLambda = memoize(function inferTypeLambda(s: LambdaBlockSt
|
||||||
|
|
||||||
// Given a named value whose type we know nothing about, and an expression that computes the value (which may recursively contain the value), compute the type of the value.
|
// Given a named value whose type we know nothing about, and an expression that computes the value (which may recursively contain the value), compute the type of the value.
|
||||||
// Why? Both lambda functions and let-expressions can refer to themselves recursively. To infer their type, we need to recompute the type and feed it back to itself until some fixed point is reached.
|
// Why? Both lambda functions and let-expressions can refer to themselves recursively. To infer their type, we need to recompute the type and feed it back to itself until some fixed point is reached.
|
||||||
function iterateRecursiveType(paramName: string, expr: ExprBlockState, env: StaticEnvironment, paramIsInner: boolean) {
|
function iterateRecursiveType(paramName: string, expr: ExprBlockState, env: StaticEnvironment) {
|
||||||
let [paramType] = typeUnknown(env);
|
let [paramType] = typeUnknown(env);
|
||||||
const paramTypeVar = paramType.symbol;
|
const paramTypeVar = paramType.symbol;
|
||||||
|
|
||||||
let iterations = 0;
|
let iterations = 1;
|
||||||
while (true) {
|
while (true) {
|
||||||
const innerEnv = {
|
const innerEnv = {
|
||||||
names: trie.insert(env.names)(paramName)({
|
names: trie.insert(env.names)(paramName)({kind: "unknown", t: paramType}),
|
||||||
kind: "unknown",
|
|
||||||
t: paramType,
|
|
||||||
}),
|
|
||||||
typevars: env.typevars.union(occurring(paramType) as Set<string>),
|
typevars: env.typevars.union(occurring(paramType) as Set<string>),
|
||||||
};
|
};
|
||||||
|
|
||||||
const innerTypeInfo = inferType(expr, innerEnv);
|
const innerTypeInfo = inferType(expr, innerEnv);
|
||||||
|
const subsWithoutPType = new Map(innerTypeInfo.subs);
|
||||||
|
subsWithoutPType.delete(paramTypeVar);
|
||||||
const inferredPType = substitute(paramType, innerTypeInfo.subs, []);
|
const inferredPType = substitute(paramType, innerTypeInfo.subs, []);
|
||||||
const [inferredPType2, newEnv] = rewriteInferredType(inferredPType, env);
|
const [inferredPType2, newEnv] = rewriteInferredType(inferredPType, env);
|
||||||
|
|
||||||
const subsWithoutPType = new Map(innerTypeInfo.subs); // copy
|
|
||||||
subsWithoutPType.delete(paramTypeVar);
|
|
||||||
|
|
||||||
// console.log("-----------------", iterations);
|
|
||||||
// console.log("paramType:", prettyT(paramType));
|
|
||||||
// console.log("inferredPType:", prettyT(inferredPType));
|
|
||||||
// console.log("inferredPType2:", prettyT(inferredPType2));
|
|
||||||
// console.log("env:", [...env.typevars].map(getHumanReadableName));
|
|
||||||
// console.log("innerEnv:", [...innerEnv.typevars].map(getHumanReadableName));
|
|
||||||
// console.log("-----------------");
|
|
||||||
|
|
||||||
if (eqType(inferredPType2)(paramType)) {
|
if (eqType(inferredPType2)(paramType)) {
|
||||||
return {
|
return {
|
||||||
subs: subsWithoutPType,
|
subs: subsWithoutPType,
|
||||||
|
|
@ -238,11 +216,17 @@ function iterateRecursiveType(paramName: string, expr: ExprBlockState, env: Stat
|
||||||
innerEnv,
|
innerEnv,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if ((iterations++) == 100) {
|
||||||
if ((iterations++) == 10) {
|
|
||||||
throw new Error("too many iterations! something's wrong!");
|
throw new Error("too many iterations! something's wrong!");
|
||||||
}
|
}
|
||||||
paramType = inferredPType2; // next iteration
|
// console.log("-----------------", iterations);
|
||||||
|
// console.log("paramType:", prettyT(paramType));
|
||||||
|
// console.log("inferredPType:", prettyT(inferredPType));
|
||||||
|
// console.log("inferredPType2:", prettyT(inferredPType2));
|
||||||
|
// console.log("env:", [...env.typevars].map(getHumanReadableName));
|
||||||
|
// console.log("innerEnv:", [...innerEnv.typevars].map(getHumanReadableName));
|
||||||
|
// console.log("-----------------");
|
||||||
|
paramType = inferredPType2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,7 +259,7 @@ function rewriteInferredType(type: Type, env: StaticEnvironment): [Type, StaticE
|
||||||
const newTypeVars = new Set(env.typevars);
|
const newTypeVars = new Set(env.typevars);
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (const o of occurring(type)) {
|
for (const o of occurring(type)) {
|
||||||
while (newTypeVars.has(UNBOUND_SYMBOLS[i])) {
|
while (env.typevars.has(UNBOUND_SYMBOLS[i])) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (!env.typevars.has(o)) {
|
if (!env.typevars.has(o)) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue