improve type inferencing + fix bug in CallBlock suggestion priorities

This commit is contained in:
Joeri Exelmans 2025-05-18 10:33:43 +02:00
parent 24689b3783
commit c45f19143b
6 changed files with 156 additions and 765 deletions

View file

@ -17,11 +17,11 @@
"react-dom": "^19.1.0"
},
"devDependencies": {
"@eslint/js": "^9.26.0",
"@eslint/js": "^9.27.0",
"@types/react": "^19.1.4",
"@types/react-dom": "^19.1.5",
"@vitejs/plugin-react-swc": "^3.9.0",
"eslint": "^9.26.0",
"eslint": "^9.27.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.1.0",

887
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -79,7 +79,7 @@ function FunctionHeader({ state, setState, suggestionPriority }) {
setState={setFn}
suggestionPriority={(fnSuggestion: ResolvedType) => computePriority(
fnSuggestion,
evalEditorBlock(state.fn.input, env),
evalEditorBlock(state.input, env),
suggestionPriority,
env,
)}

View file

@ -10,6 +10,11 @@
display: inline-block;
}
*:hover:not(:has(> *:hover)) {
/* useful for debugging: */
/* border-width: 2px !important; */
}
.offending .error {
background-color: transparent;
}

View file

@ -54,6 +54,7 @@ const computeSuggestions = (text, env, suggestionPriority: (s: ResolvedType) =>
}]),
]
// return ls;
// return [];
return ls
.map(suggestion => [suggestionPriority(suggestion[2]), ...suggestion] as PrioritizedSuggestionType)
.sort(([priorityA], [priorityB]) => priorityB - priorityA)

View file

@ -97,11 +97,11 @@ export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: Resolved
}
try {
// fn is a function...
const [outType, substitutions] = assignFnSubstitutions(fnResolved.t, inputResolved.t); // may throw
const [_inType, inSubst, outType, _outSubst] = assignFnSubstitutions(fnResolved.t, inputResolved.t, getUnusedTypeVarIdx(env)); // may throw
// console.log('assignFn...', prettyT(fnResolved.t), inputResolved.i, prettyT(inputResolved.t), '\nout =', prettyT(outType), substitutions);
// 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(substitutions, fnResolved.substitutions, inputResolved.substitutions);
const mergedSubstitutions = mergeMaps(inSubst, fnResolved.substitutions, inputResolved.substitutions);
if (inputResolved.kind === "error") {
return {
@ -171,14 +171,18 @@ export function evalLetInBlock(value: EditorState, name: string, inner: EditorSt
return evalEditorBlock(inner, innerEnv);
}
export function getUnusedTypeVar(env) {
function getUnusedTypeVarIdx(env) {
for (let i=0; ; i++) {
if (!dict.has(env.typeDict)(TYPE_VARS[i])) {
return TYPE_VARS[i];
return i;
}
}
}
export function getUnusedTypeVar(env) {
return TYPE_VARS[getUnusedTypeVarIdx(env)];
}
export function evalLambdaBlock(paramName: string, expr: EditorState, env): ResolvedType {
const paramType = getUnusedTypeVar(env);
// static env: we only know the name and the type
@ -187,11 +191,6 @@ export function evalLambdaBlock(paramName: string, expr: EditorState, env): Reso
t: paramType,
substitutions: new Map(),
})
// const staticInnerEnv = makeInnerEnv(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);
const lambdaTSubstituted = substitute(lambdaT, exprResolved.substitutions, []);
@ -202,7 +201,8 @@ export function evalLambdaBlock(paramName: string, expr: EditorState, env): Reso
t: lambdaTSubstituted,
depth: 0,
e: exprResolved.e,
substitutions: staticInnerEnv.substitutions,
// substitutions: new Map(),
substitutions: exprResolved.substitutions,
}
}
const paramTypeSubstituted = lambdaTSubstituted.params[0](lambdaTSubstituted);