Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
72df8b4
Added visualization of calculator/requirement dependencies and added …
PaulKlint Apr 18, 2026
263f25c
Fixed error in addReturnTypeDependency; added dependencies
PaulKlint Apr 21, 2026
727f880
Added dependencies
PaulKlint Apr 21, 2026
8d82e83
Added dependencies
PaulKlint Apr 21, 2026
0fecd2d
Commented out viewDependencies
PaulKlint Apr 21, 2026
b2c5afd
Commented out viewDependencies
PaulKlint Apr 21, 2026
96b2ac0
Tests
PaulKlint Apr 21, 2026
bf59178
Removed dependencies
PaulKlint Apr 21, 2026
05703d5
Fixed type error
PaulKlint Apr 21, 2026
7908765
Added missing import
PaulKlint Apr 21, 2026
2c6ca40
Fixed test to the breaking case
DavyLandman Apr 22, 2026
5a31df3
Fixed handling of FunctionTypes in a signature
PaulKlint Apr 30, 2026
8ecf960
Minor fixes
PaulKlint Apr 30, 2026
b4924da
Fixed incorrect type + cleanup
PaulKlint Apr 30, 2026
e2a904e
Cleanup
PaulKlint Apr 30, 2026
e47dca3
Removed no longer used function
PaulKlint Apr 30, 2026
bccf558
Added type info
PaulKlint Apr 30, 2026
35e2138
Test cases
PaulKlint Apr 30, 2026
7e60879
Merge branch 'main' into fix/visualize-and-add-missing-dependencies
PaulKlint Apr 30, 2026
f36c5bc
Special case for type parameter in nested function declaration.
PaulKlint Apr 30, 2026
38c890f
Return statement should depend on complete signature (not return type)
PaulKlint May 3, 2026
0d5c7cc
Fixed treatment of closures
PaulKlint May 3, 2026
579177f
Removed dependencies
PaulKlint May 3, 2026
070d309
Fixed typo in message
PaulKlint May 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/org/rascalmpl/compiler/lang/rascalcore/check/AType.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,8 @@ bool asubtype(a:anode(list[AType] l), AType b){
return true;
case anode(list[AType] r):
return l <= r;
case adt: aadt(str _, list[AType] _, _):
return true;
case \start(t):
return asubtype(a, t);
case avalue():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ void collect(current: (FunctionDeclaration) `<FunctionDeclaration decl>`, Collec
c.enterLubScope(decl);
collect(decl.tags, c);
scope = c.getScope();
c.setScopeInfo(scope, functionScope(), signatureInfo(signature.\type));
c.setScopeInfo(scope, functionScope(), signatureInfo(signature));
<tpnames, tpbounds> = collectSignature(decl.signature, c);

dt = defType([signature], AType(Solver s) {
Expand Down Expand Up @@ -389,7 +389,7 @@ void collect(current: (FunctionDeclaration) `<FunctionDeclaration decl>`, Collec
// We do in this case not check that the type of the expression as a whole is compatible with the return type.
// TODO: cover the case that we leave the expression via a return AND via the value of the expression as a whole
} else {
c.require("check on return type `<fname>`", decl.expression, [decl.expression], makeReturnRequirement(decl.expression, signature.\type));
c.require("check on return type `<fname>`", decl.expression, [decl.expression, signature], makeReturnRequirement(decl.expression, signature));
}
collect(decl.expression, c);
}
Expand Down Expand Up @@ -439,6 +439,7 @@ str md5Contrib4signature(Signature signature){
tuple[set[str], rel[str,Type]] collectSignature(Signature signature, Collector c){
returnType = signature.\type;
parameters = signature.parameters;
formals = getFormals(parameters);
kwFormals = getKwFormals(parameters);

beginUseTypeParameters(c, closed=true);
Expand Down Expand Up @@ -474,6 +475,16 @@ tuple[set[str], rel[str,Type]] collectSignature(Signature signature, Collector c
formalsList = [ updateBounds(fm, minB) | fm <- formalsList ];
kwFormalsList = [ kwf[fieldType = updateBounds(kwf.fieldType, minB)] | kwf <- computeKwFormals(kwFormals, s) ];
ft = afunc(rtU, formalsList, kwFormalsList);
if(!isEmpty(tpnames)){
for(int i <- index(formalsList)){
s.fact(formals[i], formalsList[i]);
// println("*** add fact: <formals[i]> =\> <formalsList[i]>");
}
for(int i <- index(kwFormalsList)){
s.fact( kwFormals[i], kwFormalsList[i].fieldType);
// println("*** add fact: <kwFormals[i]> =\> <kwFormalsList[i].fieldType>");
}
}
//ft = updateBounds(afunc(s.getType(returnType), formalsList, computeKwFormals(kwFormals, s)), minB);
return ft;
});
Expand Down Expand Up @@ -552,7 +563,7 @@ private tuple[set[str], rel[str,Type]] computeBoundsAndDefineTypeParams(Signatur
// during collection. We cannot declare or use type parameters as they are encountered during collect
// since their open/closed status has to be taken into account and that depends on the more global
// context of the signature or function declaration in which they occur. That is why we explicitly create
// uses and defs nof type parameters.
// uses and defs for type parameters.

typeParamsInParameters = [*getTypeParams(t) | t <- formals + kwFormals];

Expand All @@ -572,6 +583,7 @@ private tuple[set[str], rel[str,Type]] computeBoundsAndDefineTypeParams(Signatur
c.use(tpbound.name, {typeVarId()});
}
}
seenInReturn += "<tp.name>";
c.use(tp.name, {typeVarId()});
c.calculate("typevar in result type", tp, [tp.name], makeTypeGetter(tp,closed=true));
}
Expand All @@ -592,13 +604,20 @@ private tuple[set[str], rel[str,Type]] computeBoundsAndDefineTypeParams(Signatur
c.define(tpname, typeVarId(), tp.name,
defType(toList(typeParamBounds[tpname]), makeBoundDef(tp, typeParamBounds, closed=false)));
c.fact(tp, tp.name);
// c.calculate("bounded type var", tp, [tp], makeTypeGetter(tp));
}
}

// Due to their special treatment, missing type parameters are not detected by typepal but have to
// detected explicitly.
// be detected explicitly.

missing = seenInReturn - seenInParams;
for(TypeVar x <- typeParamsInReturn){
xname = "<x.name>";
if(xname in missing && c.isAlreadyDefined(xname, x)){
missing -= xname;
}
}
if(!isEmpty(missing)){
missing = {"&<m>" | m <- missing };
c.report(error(signature, "Type parameter(s) %v in return type of function %q not bound by its formal parameters", missing, signature.name));
Expand All @@ -624,7 +643,7 @@ void collect(Parameters parameters, Collector c){
} else {
scope = c.getScope();

c.calculate("formals", parameters, [],
c.calculate("formals", parameters, [], //formals+kwFormals,
AType(Solver s) {
formalTypes = [ getPatternType(f, avalue(), scope, s) | f <- formals ];
int last = size(formalTypes) -1;
Expand All @@ -641,18 +660,33 @@ void collect(Parameters parameters, Collector c){
endPatternScope(c);
}

void(Solver) makeReturnRequirement(Tree returnExpr, Type returnType)
void(Solver) makeReturnRequirement(Tree returnExpr, Signature signature)
= void(Solver s){
returnRequirement(returnExpr, s.getType(returnType), s);
returnRequirement(returnExpr, signature, s);
};

void(Solver) makeReturnRequirement(Tree returnExpr, AType returnAType)
void(Solver) makeReturnRequirement(Tree returnExpr, Type returnType)
= void(Solver s){
returnRequirement(returnExpr, returnAType, s);
returnRequirement(returnExpr, s.getType(returnType), s);
};


// void(Solver) makeReturnRequirement(Tree returnExpr, AType returnAType, Parameters parameters)
// = void(Solver s){
// returnRequirement(returnExpr, parameters, returnAType, s);
// };

void returnRequirement(Tree returnExpr, Signature signature, Solver s){
sigType = s.getType(signature);
declaredReturnType = sigType.ret;
returnRequirement(returnExpr, s.getType(declaredReturnType), s);
}

void returnRequirement(Tree returnExpr, AType declaredReturnType, Solver s){
// sigType = s.getType(signature);
// declaredReturnType = sigType.ret;
returnExprType = s.getType(returnExpr);
// println("returnRequirement: <returnExpr>, declared: <declaredReturnType>, actual: <returnExprType>");
FailMessage msg = p:/aparameter(_,_) := declaredReturnType
? error(returnExpr, "Returned type %t is not always a subtype of expected return type %t", returnExprType, declaredReturnType)
: error(returnExpr, "Return type %t expected, found %t", declaredReturnType, returnExprType);
Expand Down Expand Up @@ -690,11 +724,17 @@ void collect(current: (Statement) `return <Statement statement>`, Collector c){
functionScopes = c.getScopeInfo(functionScope());
assert !isEmpty(functionScopes);
for(<_, scopeInfo> <- functionScopes){
if(signatureInfo(Type returnType) := scopeInfo){
c.require("check return type", current, [statement, returnType], makeReturnRequirement(statement, returnType));
if(signatureInfo(Type returnType, Parameters parameters) := scopeInfo){
c.require("check return type", current, [statement, returnType, parameters], makeReturnRequirement(statement, returnType));
c.fact(current, returnType); // Note that type of the return statement as a whole is the function's return type
collect(statement, c);
return;
} else
if(signatureInfo(Signature signature) := scopeInfo){
c.require("check return type", current, [statement, signature], makeReturnRequirement(statement, signature));
c.fact(current, signature.\type); // Note that type of the return statement as a whole is the function's return type
collect(statement, c);
return;
} else {
throw rascalCheckerInternalError(getLoc(current), "Inconsistent info from function scope: <scopeInfo>");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ void collectClosure(Expression current, Type returnType, Parameters parameters,
parentScope = c.getScope();
c.enterLubScope(current);
scope = c.getScope();
c.setScopeInfo(scope, functionScope(), signatureInfo(returnType));
clos_name = closureName(current);
c.setScopeInfo(scope, functionScope(), signatureInfo(returnType, parameters));

beginUseTypeParameters(c, closed=true);
collect(returnType, c); // any type parameters in return type remain closed (closed=true);
Expand All @@ -242,7 +243,7 @@ void collectClosure(Expression current, Type returnType, Parameters parameters,

collect(stats, c); // TODO take parameter bounds into account!

clos_name = closureName(current);

bool returnsViaAll = returnsViaAllPath(stats, clos_name, c);
formals = getFormals(parameters);
kwFormals = getKwFormals(parameters);
Expand Down Expand Up @@ -454,7 +455,7 @@ void collect(current: (Comprehension) `[ <{Expression ","}+ results> | <{Express
try {
c.fact(current, makeListType(lubList([ c.getType(r) | r <- res])));
} catch TypeUnavailable(): {
c.calculate("list comprehension results", current, res,
c.calculate("list comprehension results", current, gens + res,
AType(Solver s){
return makeListType(lubList([ s.getType(r) | r <- res]));
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ void collect(current: (Pattern) `{ <{Pattern ","}* elements0> }`, Collector c){
}
c.push(patternContainer, "set");
collect(elements0, c);
c.calculate("set pattern", current, [e | e <- elements0],
AType (Solver s){ return aset(lubList([s.getType(e) | e <- elements0])); });
c.pop(patternContainer);
}

Expand All @@ -82,6 +84,8 @@ void collect(current: (Pattern) `[ <{Pattern ","}* elements0> ]`, Collector c){
}
c.push(patternContainer, "list");
collect(elements0, c);
c.calculate("list pattern", current, [e | e <- elements0],
AType (Solver s){ return alist(lubList([s.getType(e) | e <- elements0])); });
c.pop(patternContainer);
}

Expand All @@ -92,21 +96,8 @@ void collect(current: (Pattern) `<Type tp> <Name name>`, Collector c){
if(tp is function) c.enterScope(current);
collect(tp, c);
if(tp is function) c.leaveScope(current);
calcDeps = [tp];
functionScopes = c.getScopeInfo(functionScope());
if(!isEmpty(functionScopes)){
for(<_, scopeInfo> <- functionScopes){
if(signatureInfo(Type returnType) := scopeInfo){
calcDeps += returnType;
break;
} else {
throw rascalCheckerInternalError(getLoc(current), "Inconsistent info from function scope: <scopeInfo>");
}
}
}
c.calculate("typed variable pattern", current, calcDeps, AType(Solver s){ return s.getType(tp)[alabel=uname]; });
c.calculate("typed variable pattern", current, [tp], AType(Solver s){ return s.getType(tp)[alabel=uname]; });


if(!isWildCard(uname)){
c.push(patternNames, <uname, getLoc(name)>);
orScopes = c.getScopeInfo(orScope());
Expand All @@ -120,7 +111,7 @@ void collect(current: (Pattern) `<Type tp> <Name name>`, Collector c){
}
c.define(uname, formalOrPatternFormal(c), name, defType(tp));
} else {
c.fact(name, tp);
c.calculate("variable <name>", name, [tp], AType(Solver s) { return s.getType(tp); });
}
}

Expand Down
14 changes: 8 additions & 6 deletions src/org/rascalmpl/compiler/lang/rascalcore/check/CollectType.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,6 @@ void collect(current:(TypeVar) `& <Name n>`, Collector c){

void collect(current: (TypeVar) `& <Name n> \<: <Type tp>`, Collector c){
pname = prettyPrintName(n);

if(<true, bool closed> := defineOrReuseTypeParameters(c)){
if(c.isAlreadyDefined(pname, n)){
c.use(n, {typeVarId() });
Expand All @@ -854,23 +853,26 @@ void collect(current: (TypeVar) `& <Name n> \<: <Type tp>`, Collector c){
//if(debugTP)println("Define <pname> at <current@\loc>");
}
c.fact(current, n);
//c.calculate("type parameter, 1", current, [n, *calcDeps], AType (Solver s) { return s.getType(n)[closed=closed]; });
} else if(<true, bool closed> := useTypeParameters(c)){
c.use(n, {typeVarId() });
c.calculate("xxx", current, [n], AType (Solver s) { return s.getType(n)[closed=closed]; });
c.fact(current, tp);
// c.calculate("type parameter, 2", current, [n, tp], AType (Solver s) {
// return s.getType(n)[closed=closed]; });
//if(debugTP)println("Use <pname> at <current@\loc>");
} else if(<true, rel[str, Type] tpbounds> := useBoundedTypeParameters(c)){
if(!isEmpty(tpbounds[pname])){
bnds = toList(tpbounds[pname]);
c.calculate("type parameter with bound", n, bnds,
c.calculate("type parameter with bound, 1", n, bnds + [tp],
AType(Solver s){
new_bnd = (avalue() | aglb(it, s.getType(bnd)) | bnd <- bnds);
return aparameter(prettyPrintName(n), s.getType(new_bnd), closed=true);
});
} else {
c.calculate("type parameter with bound", n, [tp], AType(Solver s){ return aparameter(prettyPrintName(n), s.getType(tp), closed=true); });
c.calculate("type parameter with bound, 2", n, [tp], AType(Solver s){ return aparameter(prettyPrintName(n), s.getType(tp), closed=true); });
}
c.fact(current, n);
}
c.fact(current, tp);
}

collect(tp, c);
}
Expand Down
Loading
Loading