Skip to content

Commit

Permalink
Fixed handling of type parameters in keyword parameters of constructors
Browse files Browse the repository at this point in the history
Fixes #2025
  • Loading branch information
PaulKlint committed Sep 14, 2024
1 parent a90077c commit ce5703d
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,32 @@ void dataDeclaration(Tags tags, Declaration current, list[Variant] variants, Col
AType(Solver) makeFieldType(str fieldName, Tree fieldType)
= AType(Solver s) { return s.getType(fieldType)[alabel=fieldName]; };

AType(Solver) makeKeywordFieldType(str fieldName, KeywordFormal kwf)
= AType(Solver s) {
fldType = s.getType(kwf.\type);
defType = s.getType(kwf.expression);
bindings = ();
try bindings = unifyRascalTypeParams(fldType, defType, bindings);
catch invalidMatch(str reason):
s.report(error(current, reason));

if(!isEmpty(bindings)){
try {
fldType = instantiateRascalTypeParameters(kwf.\type, fldType, bindings, s);
} catch invalidInstantiation(str msg): {
s.report(error(kwf, "Cannot instantiate keyword parameter type `<prettyAType(fldType)>`: " + msg));
}
try {
defType = instantiateRascalTypeParameters(kwf.expression, defType, bindings, s);
} catch invalidInstantiation(str msg): {
s.report(error(kwf, "Cannot instantiate type of default expression `<prettyAType(defType)>`: " + msg));
}
}
s.requireSubType(defType, fldType, error(kwf.expression, "Default expression of type %t expected, found %t", fldType, defType));

return fldType[alabel=fieldName];
};

int variantCounter = 0;

void collect(current:(Variant) `<Name name> ( <{TypeArg ","}* arguments> <KeywordFormals keywordArguments> )`, Collector c){
Expand Down Expand Up @@ -101,10 +127,9 @@ void collect(current:(Variant) `<Name name> ( <{TypeArg ","}* arguments> <Keywor
if(fieldName in declaredFieldNames) c.report(error(kwf, "Double declaration of field `%v`", fieldName));
declaredFieldNames += fieldName;
kwfType = kwf.\type;
dt = defType([kwfType], makeFieldType(fieldName, kwfType));
dt = defType([kwfType], makeKeywordFieldType(fieldName, kwf));
dt.md5 = md5Hash("<currentModuleName><adtName><dataCounter><name><consArity><kwfType><fieldName>");
c.define(fieldName, keywordFieldId(), kwf.name, dt);
c.requireSubType(kwf.expression, kwfType, error(kwf, "Default expression of type %t expected, found %t", kwfType, kwf.expression));
}

scope = c.getScope();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,24 @@ private void checkAssignment(Statement current, (Assignable) `<QualifiedName nam
AType(Solver s) {
nameType = s.getType(name);
asgType = computeAssignmentRhsType(current, nameType, operator, s.getType(statement), s);

bindings = ();
try bindings = unifyRascalTypeParams(nameType, asgType, bindings);
catch invalidMatch(str reason):
s.report(error(current, reason));

if(!isEmpty(bindings)){
try {
nameType = instantiateRascalTypeParameters(name, nameType, bindings, s);
} catch invalidInstantiation(str msg): {
s.report(error(current, "Cannot instantiate lhs type `<prettyAType(nameType)>` of assignment: " + msg));
}
try {
asgType = instantiateRascalTypeParameters(statement, asgType, bindings, s);
} catch invalidInstantiation(str msg): {
s.report(error(current, "Cannot instantiate rhs type `<prettyAType(defType)>` of assignment: " + msg));
}
}
if(operator == "=")
s.requireComparable(asgType, nameType, error(current, "Incompatible type %t in assignment to %t variable %q", asgType, nameType, "<name>"));
return asgType;
Expand Down Expand Up @@ -934,15 +952,39 @@ private void checkAssignment(Statement current, asg: (Assignable) `<Assignable r
//collect(receiver, c);
}

private void requireAssignmentSubType(Tree current, AType a, AType b, FailMessage msg, Solver s){
bindings = ();
try bindings = unifyRascalTypeParams(a, b, bindings);
catch invalidMatch(str reason):
s.report(error(current, reason));

if(!isEmpty(bindings)){
try {
a = instantiateRascalTypeParameters(current, a, bindings, s);
} catch invalidInstantiation(str msg): {
s.report(error(current, "Cannot instantiate type `<prettyAType(a)>`: " + msg));
}
try {
b = instantiateRascalTypeParameters(current, b, bindings, s);
} catch invalidInstantiation(str msg): {
s.report(error(current, "Cannot instantiate type `<prettyAType(b)>`: " + msg));
}
}
s.requireSubType(a, b, msg);
}

private AType computeFieldAssignableType(Statement current, AType receiverType, Tree field, str operator, AType rhs, loc scope, Solver s){
fieldName = unescape("<field>");
if(isNonTerminalAType(receiverType) && fieldName == "top"){
return isStartNonTerminalType(receiverType) ? getStartNonTerminalType(receiverType) : receiverType;
}
fieldType = s.getTypeInType(receiverType, field, {fieldId(), keywordFieldId()}, scope);
updatedFieldType = computeAssignmentRhsType(current, fieldType, operator, rhs, s);
s.requireSubType(updatedFieldType, fieldType, error(current, "Field %q requires %t, found %t", fieldName, fieldType, updatedFieldType));
return updatedFieldType;
requireAssignmentSubType(current, updatedFieldType, fieldType, error(current, "Field %q requires %t, found %t", fieldName, fieldType, updatedFieldType), s);

//s.requireSubType(updatedFieldType, fieldType, error(current, "Field %q requires %t, found %t", fieldName, fieldType, updatedFieldType));
//return updatedFieldType;
return fieldType;
}

private void checkAssignment(Statement current, asg: (Assignable) `<Assignable receiver> ? <Expression defaultExpression>`, str operator, Statement rhs, Collector c){
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,74 @@
module lang::rascalcore::compile::Examples::Tst4

import util::Maybe;

int f() = X;
test bool nothingStrEqual(){
Maybe[str] x = nothing();
Maybe[str] y = nothing();
return x == nothing() && y == nothing() && x == y;
}

int Y = X + 1;
int X = 2;
value main() = X + Y;
test bool just2nothing(){
x = just(3);
x = nothing();
return x == nothing();
}

test bool inc1(){
Maybe[int] x = just(3);
x.val += 1;
return x.val == 4;
}

test bool inc2(){
x = just(3);
x.val += 1;
return x.val == 4;
}

test bool inc3(){
x = just((1 : "a"));
x.val[1] ? "aaa" += "xxx";
return x.val == (1:"axxx");
}

test bool inc4(){
x = just((1 : "a"));
x.val[2] ? "aaa" += "xxx";
return x.val == (1:"a",2:"aaaxxx");
}

data X = contain(
Maybe[bool] p,
Maybe[int] kw1 = just(2),
Maybe[str] kw2 = nothing()
);

test bool contain1(){
c = contain(nothing());
return c.p == nothing() && c.kw1.val == 2 && c.kw2 == nothing();
}

test bool contain2(){
c = contain(nothing(), kw1 = nothing(), kw2 = just("hi"));
return c.p == nothing() && c.kw1 == nothing() && c.kw2 == just("hi");
}

test bool contain3(){
c = contain(nothing());
c.kw1 = nothing();
c.kw2 = just("hi");
return c.p == nothing() && c.kw1 == nothing() && c.kw2 == just("hi");
}

//data D = d(int n);
//
//value main(){
// x = d(1);
// num y = 3;
// x.n = y;
// return 0;
//}


//import ParseTree;
Expand Down

0 comments on commit ce5703d

Please sign in to comment.