Simplify types in diagnostic messages and constraint-solve ALL

constraints
This commit is contained in:
Sam Vervaeck 2022-09-06 13:40:20 +02:00
parent 204d2961e3
commit 469b0cc756

View file

@ -386,6 +386,7 @@ export class Checker {
private boolType = new TCon(this.nextConTypeId++, [], 'Bool'); private boolType = new TCon(this.nextConTypeId++, [], 'Bool');
private contexts: InferContext[] = []; private contexts: InferContext[] = [];
private constraints: Constraint[] = [];
private solution = new TVSub(); private solution = new TVSub();
@ -415,27 +416,9 @@ export class Checker {
} }
private addConstraint(constraint: Constraint): void { private addConstraint(constraint: Constraint): void {
switch (constraint.kind) { this.constraints.push(constraint);
case ConstraintKind.Many: if (this.contexts.length > 0) {
{ this.contexts[this.contexts.length-1].constraints.push(constraint);
for (const element of constraint.elements) {
this.addConstraint(element);
}
return;
}
case ConstraintKind.Equal:
{
const count = this.contexts.length;
let i;
for (i = count-1; i > 0; i--) {
const typeVars = this.contexts[i].typeVars;
if (typeVars.intersectsType(constraint.left) || typeVars.intersectsType(constraint.right)) {
break;
}
}
this.contexts[i].constraints.push(constraint);
break;
}
} }
} }
@ -909,7 +892,7 @@ export class Checker {
new CEqual( new CEqual(
this.inferTypeExpression(node.typeAssert.typeExpression), this.inferTypeExpression(node.typeAssert.typeExpression),
type, type,
node.typeAssert node
) )
); );
} }
@ -976,7 +959,7 @@ export class Checker {
this.popContext(context); this.popContext(context);
this.solve(new CMany(constraints), this.solution); this.solve(new CMany(this.constraints), this.solution);
} }
private solve(constraint: Constraint, solution: TVSub): void { private solve(constraint: Constraint, solution: TVSub): void {
@ -999,14 +982,8 @@ export class Checker {
case ConstraintKind.Equal: case ConstraintKind.Equal:
{ {
if (!this.unify(constraint.left, constraint.right, solution)) { if (!this.unify(constraint.left, constraint.right, solution, constraint)) {
this.diagnostics.add( // TODO break or continue?
new UnificationFailedDiagnostic(
constraint.left.substitute(solution),
constraint.right.substitute(solution),
[...constraint.getNodes()],
)
);
} }
break; break;
} }
@ -1016,7 +993,7 @@ export class Checker {
} }
private unify(left: Type, right: Type, solution: TVSub): boolean { private unify(left: Type, right: Type, solution: TVSub, constraint: CEqual): boolean {
if (left.kind === TypeKind.Var && solution.has(left)) { if (left.kind === TypeKind.Var && solution.has(left)) {
left = solution.get(left)!; left = solution.get(left)!;
@ -1035,7 +1012,7 @@ export class Checker {
} }
if (right.kind === TypeKind.Var) { if (right.kind === TypeKind.Var) {
return this.unify(right, left, solution); return this.unify(right, left, solution, constraint);
} }
if (left.kind === TypeKind.Any || right.kind === TypeKind.Any) { if (left.kind === TypeKind.Any || right.kind === TypeKind.Any) {
@ -1050,38 +1027,45 @@ export class Checker {
let success = true; let success = true;
const count = left.paramTypes.length; const count = left.paramTypes.length;
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
if (!this.unify(left.paramTypes[i], right.paramTypes[i], solution)) { if (!this.unify(left.paramTypes[i], right.paramTypes[i], solution, constraint)) {
success = false; success = false;
} }
} }
if (!this.unify(left.returnType, right.returnType, solution)) { if (!this.unify(left.returnType, right.returnType, solution, constraint)) {
success = false; success = false;
} }
return success; return success;
} }
if (left.kind === TypeKind.Arrow && left.paramTypes.length === 0) { if (left.kind === TypeKind.Arrow && left.paramTypes.length === 0) {
return this.unify(left.returnType, right, solution); return this.unify(left.returnType, right, solution, constraint);
} }
if (right.kind === TypeKind.Arrow) { if (right.kind === TypeKind.Arrow) {
return this.unify(right, left, solution); return this.unify(right, left, solution, constraint);
} }
if (left.kind === TypeKind.Con && right.kind === TypeKind.Con) { if (left.kind === TypeKind.Con && right.kind === TypeKind.Con) {
if (left.id !== right.id) { if (left.id === right.id) {
return false; assert(left.argTypes.length === right.argTypes.length);
} const count = left.argTypes.length;
assert(left.argTypes.length === right.argTypes.length); let success = true;
const count = left.argTypes.length; for (let i = 0; i < count; i++) {
for (let i = 0; i < count; i++) { if (!this.unify(left.argTypes[i], right.argTypes[i], solution, constraint)) {
if (!this.unify(left.argTypes[i], right.argTypes[i], solution)) { success = false;
return false; }
} }
return success;
} }
return true;
} }
this.diagnostics.add(
new UnificationFailedDiagnostic(
left.substitute(solution),
right.substitute(solution),
[...constraint.getNodes()],
)
);
return false; return false;
} }