From ce5703dc52164acae035d45d5a466b4cdd2a89a0 Mon Sep 17 00:00:00 2001 From: paulklint Date: Sat, 14 Sep 2024 19:41:58 +0200 Subject: [PATCH] Fixed handling of type parameters in keyword parameters of constructors Fixes #2025 --- .../check/CollectDataDeclaration.rsc | 29 +++++++- .../rascalcore/check/CollectStatement.rsc | 46 +++++++++++- .../lang/rascalcore/compile/Examples/Tst4.rsc | 71 +++++++++++++++++-- 3 files changed, 138 insertions(+), 8 deletions(-) diff --git a/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectDataDeclaration.rsc b/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectDataDeclaration.rsc index 3f370fcd..71de12d3 100644 --- a/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectDataDeclaration.rsc +++ b/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectDataDeclaration.rsc @@ -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 ``: " + msg)); + } + try { + defType = instantiateRascalTypeParameters(kwf.expression, defType, bindings, s); + } catch invalidInstantiation(str msg): { + s.report(error(kwf, "Cannot instantiate type of default expression ``: " + 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) ` ( <{TypeArg ","}* arguments> )`, Collector c){ @@ -101,10 +127,9 @@ void collect(current:(Variant) ` ( <{TypeArg ","}* arguments> "); 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(); diff --git a/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectStatement.rsc b/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectStatement.rsc index 162ff4d8..323863a2 100644 --- a/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectStatement.rsc +++ b/src/org/rascalmpl/core/library/lang/rascalcore/check/CollectStatement.rsc @@ -708,6 +708,24 @@ private void checkAssignment(Statement current, (Assignable) `` of assignment: " + msg)); + } + try { + asgType = instantiateRascalTypeParameters(statement, asgType, bindings, s); + } catch invalidInstantiation(str msg): { + s.report(error(current, "Cannot instantiate rhs type `` of assignment: " + msg)); + } + } if(operator == "=") s.requireComparable(asgType, nameType, error(current, "Incompatible type %t in assignment to %t variable %q", asgType, nameType, "")); return asgType; @@ -934,6 +952,27 @@ private void checkAssignment(Statement current, asg: (Assignable) ``: " + msg)); + } + try { + b = instantiateRascalTypeParameters(current, b, bindings, s); + } catch invalidInstantiation(str msg): { + s.report(error(current, "Cannot instantiate type ``: " + 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(""); if(isNonTerminalAType(receiverType) && fieldName == "top"){ @@ -941,8 +980,11 @@ private AType computeFieldAssignableType(Statement current, AType 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) ` ? `, str operator, Statement rhs, Collector c){ diff --git a/src/org/rascalmpl/core/library/lang/rascalcore/compile/Examples/Tst4.rsc b/src/org/rascalmpl/core/library/lang/rascalcore/compile/Examples/Tst4.rsc index 3f271f99..dacd1082 100644 --- a/src/org/rascalmpl/core/library/lang/rascalcore/compile/Examples/Tst4.rsc +++ b/src/org/rascalmpl/core/library/lang/rascalcore/compile/Examples/Tst4.rsc @@ -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;