From 433ad5dc9148d1cb77cf6df88a31ff6b1271e7d2 Mon Sep 17 00:00:00 2001 From: paulklint Date: Tue, 20 Jan 2026 19:56:04 +0100 Subject: [PATCH 01/10] Fixed nearly all remaining type errors STILL TODO: 1. error("Types Maybe[&T \<: Tree] and Maybe[&A]::just(&A val) do not match",|file:///Users/paulklint/git/rascal-language-servers/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Common.rsc|(3468,4,<86,4>,<86,8>),fixes=[],causes=[]) [This could be an error in type instantiation in the type checker] 2. error("Cannot call `changed` with keyword arguments ``needsConfirmation` of type `bool``, ``description` of type `str`` and ``label` of type `str``, given definitions `FileSystemChange(list[TextEdit]), FileSystemChange::changed(loc file, list[TextEdit] edits) or FileSystemChange::changed(loc file)`",|file:///Users/paulklint/git/rascal-language-servers/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc|(2198,122,<55,25>,<55,147>),fixes=[],causes=[]) [Simple error] 3. error("No definition found for anno, keywordfield or field `top` in type `Module`",|file:///Users/paulklint/git/rascal-language-servers/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc|(2499,3,<58,44>,<58,47>),fixes=[],causes=[]) [Unclear] 4. error("Return type `int` expected, found `num`",|file:///Users/paulklint/git/rascal-language-servers/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Benchmark.rsc|(4637,56,<72,15>,<72,71>),fixes=[],causes=[]) [Simple error] --- .../library/demo/lang/pico/LanguageServer.rsc | 4 +- .../lsp/lang/rascal/lsp/refactor/Rename.rsc | 11 +++-- .../lsp/refactor/rename/Constructors.rsc | 2 +- .../rascal/lsp/refactor/rename/Fields.rsc | 4 +- .../rascal/lsp/refactor/rename/Functions.rsc | 2 +- .../rascal/lsp/refactor/rename/Grammars.rsc | 7 +-- .../rascal/lsp/refactor/rename/Modules.rsc | 47 ++++++++++--------- .../rascal/lsp/refactor/rename/Parameters.rsc | 2 +- .../lang/rascal/lsp/refactor/rename/Types.rsc | 8 ++-- .../rascal/lsp/refactor/rename/Variables.rsc | 4 +- .../lang/rascal/tests/rename/Benchmark.rsc | 3 +- .../lsp/lang/rascal/tests/rename/Modules.rsc | 1 + .../rascal/tests/rename/ProjectOnDisk.rsc | 2 +- .../lsp/lang/rascal/tests/rename/Types.rsc | 2 +- 14 files changed, 53 insertions(+), 46 deletions(-) diff --git a/rascal-lsp/src/main/rascal/library/demo/lang/pico/LanguageServer.rsc b/rascal-lsp/src/main/rascal/library/demo/lang/pico/LanguageServer.rsc index b5aec9e81..76c12cd9e 100644 --- a/rascal-lsp/src/main/rascal/library/demo/lang/pico/LanguageServer.rsc +++ b/rascal-lsp/src/main/rascal/library/demo/lang/pico/LanguageServer.rsc @@ -177,11 +177,11 @@ set[loc] picoDefinitionService([*_, Id use, *_, start[Program] input]) = { def.s @synopsis{If a variable is not defined, we list a fix of fixes to replace it with a defined variable instead.} list[CodeAction] prepareNotDefinedFixes(loc src, rel[str, loc] defs) - = [action(title="Change to >", edits=[changed(src.top, [replace(src, existing<0>)])]) | existing <- defs]; + = [CodeAction::action(title="Change to >", edits=[changed(src.top, [replace(src, existing<0>)])]) | existing <- defs]; @synopsis{Finds a declaration that the cursor is on and proposes to remove it.} list[CodeAction] picoCodeActionService([*_, IdType x, *_, start[Program] program]) - = [action(command=removeDecl(program, x, title="remove "))]; + = [CodeAction::action(command=removeDecl(program, x, title="remove "))]; default list[CodeAction] picoCodeActionService(Focus _focus) = []; diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc index 4044a098c..408f71953 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc @@ -49,6 +49,7 @@ import String; import lang::rascal::\syntax::Rascal; import lang::rascalcore::check::Checker; +import lang::rascalcore::check::ATypeBase; import lang::rascalcore::check::BasicRascalConfig; import lang::rascal::lsp::refactor::rename::Common; @@ -69,6 +70,8 @@ import util::LanguageServer; import util::Maybe; import util::Reflective; +import analysis::diff::edits::TextEdits; + private bool isQualifiedUse(loc use, Define _:<_, str id, _, _, _, _>) = size(id) != use.length; void rascalCheckCausesOverlappingDefinitions(set[Define] currentDefs, str newName, Tree tr, TModel tm, Renamer r) { @@ -136,7 +139,7 @@ void rascalCheckCausesOverlappingDefinitions(set[Define] currentDefs, str newNam void rascalCheckLegalNameByRole(Define _:<_, _, _, role, at, dt>, str name, Renamer r) { escName = normalizeEscaping(name); - = asType(role, dt); + = asRoleType(role, dt); if (tryParseAs(t, escName) is nothing) { r.msg(error(at, " is not a valid ")); } @@ -215,7 +218,7 @@ Tree findCursorInTree(Tree t, loc cursorLoc) { } @synopsis{Due to how the focus list is computed and the grammar for concrete syntax, we cannot easily find the exact name that the cursor is at.} -list[Tree] extendFocusWithConcreteSyntax([Concrete c, *tail], loc cursorLoc) = [findCursorInTree(c, cursorLoc), c, *tail]; +list[Tree] extendFocusWithConcreteSyntax([Concrete c, *Tree tail], loc cursorLoc) = [findCursorInTree(c, cursorLoc), c, *tail]; default list[Tree] extendFocusWithConcreteSyntax(list[Tree] cursor, loc _) = cursor; data AugmentComponents = augmentUses() | augmentDefs(); @@ -229,7 +232,7 @@ TModel getConditionallyAugmentedTModel(loc l, set[Define] defs, set[AugmentCompo : r.getConfig().tmodelForLoc(l); public Edits rascalRenameSymbol(loc cursorLoc, list[Tree] cursor, str newName, set[loc] workspaceFolders, PathConfig(loc) getPathConfig) { - ModuleStatus ms = moduleStatus({}, {}, (), [], (), [], {}, (), (), (), (), pathConfig(), tconfig()); + ModuleStatus ms = moduleStatus({}, (), [], (), [], {}, (), (), (), (), pathConfig(), tconfig()); TModel tmodelForTree(Tree tr) = tmodelForLoc(tr.src.top); @@ -354,7 +357,7 @@ tuple[set[loc], set[loc], set[loc]] findOccurrenceFiles(set[Define] defs, list[T escNewName = normalizeEscaping(newName); for ( <- defs) { hasError = false; - = asType(role, dt); + = asRoleType(role, dt); if (tryParseAs(t, escNewName) is nothing) { hasError = true; r.msg(error(cursor[0], "\'\' is not a valid ")); diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Constructors.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Constructors.rsc index 94ade97c3..e679546a4 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Constructors.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Constructors.rsc @@ -79,4 +79,4 @@ set[Define] findAdditionalConstructorDefinitions(set[Define] cursorDefs, Tree tr } // ADT constructors -tuple[type[Tree] as, str desc] asType(constructorId(), defType(acons(aadt(_, _, dataSyntax()), _, _))) = <#Name, "data constructor name">; +tuple[type[Tree] as, str desc] asRoleType(constructorId(), defType(acons(aadt(_, _, dataSyntax()), _, _))) = <#Name, "data constructor name">; diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Fields.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Fields.rsc index e25bdb0e3..4f317af9a 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Fields.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Fields.rsc @@ -144,10 +144,10 @@ TModel augmentFieldUses(Tree tr, TModel tm, TModel(loc) getModel) { } // Positional fields -tuple[type[Tree] as, str desc] asType(fieldId(), _) = <#NonterminalLabel, "field name">; +tuple[type[Tree] as, str desc] asRoleType(fieldId(), _) = <#NonterminalLabel, "field name">; // Keyword fields -tuple[type[Tree] as, str desc] asType(keywordFieldId(), _) = <#Name, "keyword field name">; +tuple[type[Tree] as, str desc] asRoleType(keywordFieldId(), _) = <#Name, "keyword field name">; bool isUnsupportedCursor(list[Tree] _: [*_, Name n1, *_, (Expression) ` has `, *_], Renamer _) = (n1 := n2); diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Functions.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Functions.rsc index 1ca767414..4d2f6ab99 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Functions.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Functions.rsc @@ -56,4 +56,4 @@ set[Define] findAdditionalDefinitions(set[Define] cursorDefs:{<_, _, _, function set[Define] findAdditionalFunctionDefinitions(set[Define] cursorDefs, TModel tm) = {tm.definitions[d] | loc d <- (tm.defines)[functionId()], rascalMayOverloadSameName(cursorDefs.defined + d, tm.definitions)}; -tuple[type[Tree] as, str desc] asType(functionId(), _) = <#Name, "function name">; +tuple[type[Tree] as, str desc] asRoleType(functionId(), _) = <#Name, "function name">; diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Grammars.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Grammars.rsc index 9e79259e5..c7f8cfb60 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Grammars.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Grammars.rsc @@ -37,6 +37,7 @@ import util::Util; import lang::rascal::\syntax::Rascal; import lang::rascalcore::check::BasicRascalConfig; +import lang::rascalcore::check::AType; import Location; @@ -61,13 +62,13 @@ void renameDefinitionUnchecked(Define d: <_, _, _, lexicalId(), _, _>, loc _, st } // Non-terminals -tuple[type[Tree] as, str desc] asType(nonterminalId(), _) = <#Nonterminal, "production name">; +tuple[type[Tree] as, str desc] asRoleType(nonterminalId(), _) = <#Nonterminal, "production name">; // Lexicals -tuple[type[Tree] as, str desc] asType(lexicalId(), _) = <#Nonterminal, "production name">; +tuple[type[Tree] as, str desc] asRoleType(lexicalId(), _) = <#Nonterminal, "production name">; // Grammar constructors -tuple[type[Tree] as, str desc] asType(constructorId(), defType(acons(aadt(_, _, syntaxRole), _, _))) = <#NonterminalLabel, "grammar constructor name"> +tuple[type[Tree] as, str desc] asRoleType(constructorId(), defType(acons(aadt(_, _, syntaxRole), _, _))) = <#NonterminalLabel, "grammar constructor name"> when !syntaxRole is dataSyntax; TModel augmentExceptProductions(Tree tr, TModel tm, TModel(loc) tmodelForLoc) { diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Modules.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Modules.rsc index 57f84c459..b5c2a4a38 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Modules.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Modules.rsc @@ -48,7 +48,7 @@ import util::PathConfig; import util::Reflective; import util::Util; -tuple[type[Tree] as, str desc] asType(moduleId(), _) = <#QualifiedName, "module name">; +tuple[type[Tree] as, str desc] asRoleType(moduleId(), _) = <#QualifiedName, "module name">; tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{<_, str defName, _, moduleId(), loc d, _>}, list[Tree] cursor, str newName, Tree(loc) getTree, Renamer r) { set[loc] useFiles = {}; @@ -72,38 +72,39 @@ tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{ } catch _: {;} for (loc f <- getSourceFiles(r)) { - m = getTree(f); + mtree = getTree(f); bool markedNew = false; bool markedUse = false; - - top-down-break visit (m.top.header.imports) { - case modNameTree: { - // Import of exact module name - useFiles += f; - markedUse = true; - } - } - bottom-up-break visit(m) { - case QualifiedName qn: { - // Import of redundantly escaped module name - qnSize = size(asNames(qn)); - if (qnSize == modNameNumberOfNames && modName == normalizeEscaping("")) { + if(Module m := mtree.top){ + top-down-break visit (m.header.imports) { + case modNameTree: { + // Import of exact module name useFiles += f; markedUse = true; } - else if (qnSize == modNameNumberOfNames + 1 || qnSize == newModNameNumberOfNames + 1) { - qualPref = qualifiedPrefix(qn); - if (qualPref.name == modName || normalizeEscaping(qualPref.name) == modName) { + } + bottom-up-break visit(m) { + case QualifiedName qn: { + // Import of redundantly escaped module name + qnSize = size(asNames(qn)); + if (qnSize == modNameNumberOfNames && modName == normalizeEscaping("")) { useFiles += f; markedUse = true; } - else if (qualPref.name == newModName || normalizeEscaping(qualPref.name) == newModName) { - newFiles += f; - markedNew = true; + else if (qnSize == modNameNumberOfNames + 1 || qnSize == newModNameNumberOfNames + 1) { + qualPref = qualifiedPrefix(qn); + if (qualPref.name == modName || normalizeEscaping(qualPref.name) == modName) { + seFiles += f; + markedUse = true; + } + else if (qualPref.name == newModName || normalizeEscaping(qualPref.name) == newModName) { + newFiles += f; + markedNew = true; + } } + if (markedUse && markedNew) continue; } - if (markedUse && markedNew) continue; } } } @@ -130,7 +131,7 @@ void renameDefinitionUnchecked(Define d:<_, currentName, _, moduleId(), _, _>, l } } -void renameAdditionalUses(set[Define] _:{<_, moduleName, _, moduleId(), modDef, _>}, str newName, TModel tm, Renamer r) { +void renameAdditionalUses(set[Define] _:{<_, moduleName, _, moduleId(), loc modDef, _>}, str newName, TModel tm, Renamer r) { // We get the module location from the uses. If there are no uses, this is skipped. // That's intended, since this function is only supposed to rename uses. if ({loc u, *_} := tm.useDef<0>) { diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Parameters.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Parameters.rsc index c0d7a75a5..733c60aa8 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Parameters.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Parameters.rsc @@ -41,7 +41,7 @@ import util::Maybe; bool isFormalId(IdRole role) = role in formalRoles; -tuple[type[Tree] as, str desc] asType(IdRole idRole, _) = <#Name, "formal parameter name"> when isFormalId(idRole); +tuple[type[Tree] as, str desc] asRoleType(IdRole idRole, _) = <#Name, "formal parameter name"> when isFormalId(idRole); tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{}, list[Tree] cursor, str newName, Tree(loc) _, Renamer _) = <{scope.top}, {scope.top}, singleNameFilter(newName)(cursor[-1]) ? {scope.top} : {}> diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Types.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Types.rsc index 26c333d71..0949e29e9 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Types.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Types.rsc @@ -88,10 +88,10 @@ public set[Define] findAdditionalDataLikeDefinitions(set[Define] defs, TModel tm }; } -tuple[type[Tree] as, str desc] asType(aliasId(), _) = <#Name, "type name">; -tuple[type[Tree] as, str desc] asType(annoId(), _) = <#Name, "annotation name">; -tuple[type[Tree] as, str desc] asType(dataId(), _) = <#Name, "ADT name">; -tuple[type[Tree] as, str desc] asType(typeVarId(), _) = <#Name, "type variable name">; +tuple[type[Tree] as, str desc] asRoleType(aliasId(), _) = <#Name, "type name">; +tuple[type[Tree] as, str desc] asRoleType(annoId(), _) = <#Name, "annotation name">; +tuple[type[Tree] as, str desc] asRoleType(dataId(), _) = <#Name, "ADT name">; +tuple[type[Tree] as, str desc] asRoleType(typeVarId(), _) = <#Name, "type variable name">; alias Environment = tuple[TModel tm, map[str, loc] defs]; diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Variables.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Variables.rsc index b455041a8..20727c699 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Variables.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Variables.rsc @@ -37,13 +37,13 @@ import analysis::typepal::TModel; import util::Maybe; // Variables -tuple[type[Tree] as, str desc] asType(variableId(), _) = <#Name, "variable name">; +tuple[type[Tree] as, str desc] asRoleType(variableId(), _) = <#Name, "variable name">; tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{}, list[Tree] cursor, str newName, Tree(loc) _, Renamer _) = <{scope.top}, {scope.top}, singleNameFilter(newName)(cursor[-1]) ? {scope.top} : {}>; // Global variables -tuple[type[Tree] as, str desc] asType(moduleVariableId(), _) = <#Name, "variable name">; +tuple[type[Tree] as, str desc] asRoleType(moduleVariableId(), _) = <#Name, "variable name">; tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{}, list[Tree] cursor, str newName, Tree(loc) getTree, Renamer r) { = filterFiles(getSourceFiles(r), "", newName, getTree); diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Benchmark.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Benchmark.rsc index af63c0159..9ef6149c2 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Benchmark.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Benchmark.rsc @@ -33,6 +33,7 @@ import List; import Set; import util::Benchmark; import util::Math; +import Message; import analysis::diff::edits::TextEdits; loc rascalProj(loc projDir) = projDir + "rascal"; @@ -68,7 +69,7 @@ map[str, num] benchmarks(loc projDir) = benchmark(( num(void()) safeRuns(int numRuns, num(list[num]) aggregate, int(void()) measure) = int(void() f) { try { - return aggregate([measure(f) | _ <- [0..numRuns]]); + return aggregate([n | _ <- [0..numRuns], num n := measure(f)]); } catch e: { println("[ERROR] "); return -1; diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Modules.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Modules.rsc index 7c3359189..119ed963f 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Modules.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Modules.rsc @@ -34,6 +34,7 @@ import Set; import lang::rascal::lsp::refactor::Rename; import lang::rascal::tests::rename::TestUtils; import lang::rascalcore::check::Checker; +import analysis::diff::edits::TextEdits; test bool deepModule() = testRenameOccurrences({ byText("some::path::to::Foo", " diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/ProjectOnDisk.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/ProjectOnDisk.rsc index 9999f87a2..fe32a1bf4 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/ProjectOnDisk.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/ProjectOnDisk.rsc @@ -54,6 +54,6 @@ Edits testProjectOnDisk(loc projectDir, str file, str oldName, int occurrence = ); } // extension for Rascal compiler - pcfg = pcfg[resources = pcfg.bin]; + pcfg = pcfg[resources = [pcfg.bin]]; return getEdits(projectDir + file, {projectDir}, occurrence, oldName, newName, PathConfig(_) { return pcfg; }); } diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Types.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Types.rsc index 76e46262a..4c8fb3da3 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Types.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Types.rsc @@ -167,7 +167,7 @@ test bool dataTypesInIIModuleStructure() = testRenameOccurrences({ 'bool func(Foo foo) = foo == g();", {}) }, oldName = "Foo", newName = "Bar"); -test bool asType() = testRenameOccurrences({0, 1}, " +test bool asRoleType() = testRenameOccurrences({0, 1}, " 'str s = \"text\"; 'if (t := [Foo] s) { ' str u = t; From ed3924614df8c1c40db7ff8def6d6571e055781f Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 21 Jan 2026 10:39:25 +0100 Subject: [PATCH 02/10] Fix rename tests - Rename missed overload. - Fix `moduleStatus` constructor call. - Fix typo in variable name. --- .../src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc | 2 +- .../main/rascal/lsp/lang/rascal/lsp/refactor/rename/Modules.rsc | 2 +- .../rascal/lsp/lang/rascal/lsp/refactor/rename/Variables.rsc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc index 408f71953..1d5486b07 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc @@ -232,7 +232,7 @@ TModel getConditionallyAugmentedTModel(loc l, set[Define] defs, set[AugmentCompo : r.getConfig().tmodelForLoc(l); public Edits rascalRenameSymbol(loc cursorLoc, list[Tree] cursor, str newName, set[loc] workspaceFolders, PathConfig(loc) getPathConfig) { - ModuleStatus ms = moduleStatus({}, (), [], (), [], {}, (), (), (), (), pathConfig(), tconfig()); + ModuleStatus ms = moduleStatus({}, {}, (), [], (), [], {}, (), (), (), (), pathConfig(), tconfig()); TModel tmodelForTree(Tree tr) = tmodelForLoc(tr.src.top); diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Modules.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Modules.rsc index b5c2a4a38..c54e08a9b 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Modules.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Modules.rsc @@ -95,7 +95,7 @@ tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{ else if (qnSize == modNameNumberOfNames + 1 || qnSize == newModNameNumberOfNames + 1) { qualPref = qualifiedPrefix(qn); if (qualPref.name == modName || normalizeEscaping(qualPref.name) == modName) { - seFiles += f; + useFiles += f; markedUse = true; } else if (qualPref.name == newModName || normalizeEscaping(qualPref.name) == newModName) { diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Variables.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Variables.rsc index 20727c699..83d6ac358 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Variables.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Variables.rsc @@ -51,7 +51,7 @@ tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{ } // Pattern variables -tuple[type[Tree] as, str desc] asType(patternVariableId(), _) = <#Name, "pattern variable name">; +tuple[type[Tree] as, str desc] asRoleType(patternVariableId(), _) = <#Name, "pattern variable name">; tuple[set[loc], set[loc], set[loc]] findOccurrenceFilesUnchecked(set[Define] _:{}, list[Tree] cursor, str newName, Tree(loc) _, Renamer _) = <{scope.top}, {scope.top}, singleNameFilter(newName)(cursor[-1]) ? {scope.top} : {}>; From bd1665954af75aeee707739e33de4f447a48a029 Mon Sep 17 00:00:00 2001 From: paulklint Date: Wed, 21 Jan 2026 11:36:49 +0100 Subject: [PATCH 03/10] Added bounds to parameterized type --- .../rascal/lsp/lang/rascal/lsp/refactor/rename/Common.rsc | 8 ++++---- rascal-lsp/src/main/rascal/lsp/util/Util.rsc | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Common.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Common.rsc index 7f22da2cb..c836a2804 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Common.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/rename/Common.rsc @@ -87,12 +87,12 @@ Tree parseAsOrEmpty(type[&T <: Tree] T, str name) = private tuple[Tree, Tree] escapePair(type[&T <: Tree] T, str n) = ; -private set[&T] escapeSet(type[&T <: Tree] T, str n) { - set[&T] res = {}; - if (just(&T t) := tryParseAs(T, n)) { +private set[&T <: Tree] escapeSet(type[&T <: Tree] T, str n) { + set[&T <: Tree] res = {}; + if (just(&T <: Tree t) := tryParseAs(T, n)) { res += t; } - if (just(&T t) := tryParseAs(T, forceEscapeSingleName(n))) { + if (just(&T <: Tree t) := tryParseAs(T, forceEscapeSingleName(n))) { res += t; } return res; diff --git a/rascal-lsp/src/main/rascal/lsp/util/Util.rsc b/rascal-lsp/src/main/rascal/lsp/util/Util.rsc index 96bc40758..ff7de007e 100644 --- a/rascal-lsp/src/main/rascal/lsp/util/Util.rsc +++ b/rascal-lsp/src/main/rascal/lsp/util/Util.rsc @@ -73,7 +73,7 @@ bool isPrefixOf(loc prefix, loc l) = l.scheme == prefix.scheme @synopsis{ Try to parse string `name` as reified type `begin` and return whether this succeeded. } -Maybe[&T] tryParseAs(type[&T <: Tree] begin, str name, bool allowAmbiguity = false) { +Maybe[&T <: Tree] tryParseAs(type[&T <: Tree] begin, str name, bool allowAmbiguity = false) { try { return just(parse(begin, name, allowAmbiguity = allowAmbiguity)); } catch ParseError(_): { From 53899ccde4139304dc6e0b489c03294943931f06 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 21 Jan 2026 11:28:02 +0100 Subject: [PATCH 04/10] Fix return type. --- .../src/main/rascal/lsp/lang/rascal/tests/rename/Benchmark.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Benchmark.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Benchmark.rsc index 9ef6149c2..9878b63dd 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Benchmark.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/Benchmark.rsc @@ -67,7 +67,7 @@ map[str, num] benchmarks(loc projDir) = benchmark(( // , "[rascal] nonterminal label": run(rascalProj(projDir), "src/org/rascalmpl/library/lang/rascal/syntax/Rascal.rsc", "lhs", newName = "lefthandside", libs = [typepalLib]) ), safeRuns(3, intMedian, realTimeOf)); -num(void()) safeRuns(int numRuns, num(list[num]) aggregate, int(void()) measure) = int(void() f) { +num(void()) safeRuns(int numRuns, num(list[num]) aggregate, int(void()) measure) = num(void() f) { try { return aggregate([n | _ <- [0..numRuns], num n := measure(f)]); } catch e: { From fae477f99acfb2dc6dcc799c7b25c0da1aec99c6 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 21 Jan 2026 11:36:55 +0100 Subject: [PATCH 05/10] Expose text edit LSP context on overload. --- rascal-lsp/src/main/rascal/library/util/LanguageServer.rsc | 7 +++++++ .../src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc | 1 + 2 files changed, 8 insertions(+) diff --git a/rascal-lsp/src/main/rascal/library/util/LanguageServer.rsc b/rascal-lsp/src/main/rascal/library/util/LanguageServer.rsc index 4df3b2916..3d3838fee 100644 --- a/rascal-lsp/src/main/rascal/library/util/LanguageServer.rsc +++ b/rascal-lsp/src/main/rascal/library/util/LanguageServer.rsc @@ -750,6 +750,13 @@ Provides extra context for all contained ((util::LanguageServer::TextEdit))s at } data FileSystemChange(str label = "", str description = "", bool needsConfirmation = false); +@synopsis{Shorthand for file changes, with additional context for LSP.} +@description{ +Provides extra context for all contained ((util::LanguageServer::TextEdit))s at once. +} +FileSystemChange changed(list[TextEdit] edits:[replace(loc l, str _), *_], str label = "", str description = "", bool needsConfirmation = false) + = changed(l.top, edits, label=label, description=description, needsConfirmation=needsConfirmation); + @synopsis{A Command is a parameter to a CommandExecutor function.} @description{ Commands can be any closed term a() pure value without open variables or function/closure values embedded in it). Add any constructor you need to express the execution parameters diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc index a6cd5b9c5..11eb87737 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc @@ -30,6 +30,7 @@ module lang::rascal::lsp::Templates import IO; import Location; import String; +import util::LanguageServer; import util::PathConfig; import util::Reflective; From bb57a4eccebb2cd9ae5644efbe45d0b4d390b781 Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 21 Jan 2026 11:37:45 +0100 Subject: [PATCH 06/10] Explicitly type start symbol. Work-around until https://github.com/usethesource/rascal/issues/2496 is fixed. --- rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc index 11eb87737..82363f729 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/Templates.rsc @@ -54,7 +54,7 @@ list[FileSystemChange] newModuleTemplates(list[loc] newFiles, PathConfig(loc) ge if (isBlank(f)) { // If the file is empty, add a module header edits += changed([replace(resetRange(f), "module \n\n")], label = "Empty module", description = "", needsConfirmation = true); - } else if (m := parseModuleWithSpaces(f)) { + } else if (start[Module] m := parseModuleWithSpaces(f)) { // If an existing module was pasted, replace the module name edits += changed([replace(m.top.header.name.src, name)], label = "Moved module", description = "", needsConfirmation = true); } From bf926d0afeccf3c84d66dacc16846f28b7594add Mon Sep 17 00:00:00 2001 From: Toine Hartman Date: Wed, 21 Jan 2026 11:41:11 +0100 Subject: [PATCH 07/10] Remove obnoxious print. --- .../src/main/rascal/lsp/lang/rascal/tests/rename/TestUtils.rsc | 2 -- 1 file changed, 2 deletions(-) diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/TestUtils.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/TestUtils.rsc index 49fd0b017..042783e1c 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/TestUtils.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/tests/rename/TestUtils.rsc @@ -156,8 +156,6 @@ bool testRenameOccurrences(set[TestModule] modules, str oldName = "foo", str new for (mm <- modules, cursorOcc <- (mm.nameOccs - mm.skipCursors)) { success = success && testProject(modules, "Test__", bool(set[TestModule] modulesByLocation, loc testDir, PathConfig pcfg) { = findCursor([m.file | m <- modulesByLocation, m.name == mm.name][0], oldName, cursorOcc); - - println("Renaming \'\' from "); = rascalRenameSymbol(cursor, focus, newName, toSet(pcfg.srcs), PathConfig(loc _) { return pcfg; }); throwMessagesIfError(msgs); From 32fb29388d53fa393ab932d04585329a9333d619 Mon Sep 17 00:00:00 2001 From: Paul Klint Date: Fri, 23 Jan 2026 14:02:22 +0100 Subject: [PATCH 08/10] Update rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc Removed space Co-authored-by: Toine Hartman --- .../src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc index 1d5486b07..b72b558a4 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc @@ -49,7 +49,7 @@ import String; import lang::rascal::\syntax::Rascal; import lang::rascalcore::check::Checker; -import lang::rascalcore::check::ATypeBase; +import lang::rascalcore::check::ATypeBase; import lang::rascalcore::check::BasicRascalConfig; import lang::rascal::lsp::refactor::rename::Common; From a01f65529c7917535f0e6afcb7b936a330f9f73b Mon Sep 17 00:00:00 2001 From: paulklint Date: Sun, 25 Jan 2026 15:53:25 +0100 Subject: [PATCH 09/10] Using generic newModuleStatus --- .../src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc index b72b558a4..916f2b3cd 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc @@ -232,7 +232,7 @@ TModel getConditionallyAugmentedTModel(loc l, set[Define] defs, set[AugmentCompo : r.getConfig().tmodelForLoc(l); public Edits rascalRenameSymbol(loc cursorLoc, list[Tree] cursor, str newName, set[loc] workspaceFolders, PathConfig(loc) getPathConfig) { - ModuleStatus ms = moduleStatus({}, {}, (), [], (), [], {}, (), (), (), (), pathConfig(), tconfig()); + ModuleStatus ms = newModuleStatus(); TModel tmodelForTree(Tree tr) = tmodelForLoc(tr.src.top); From 6060a3d5b953dff32958fdd3c45583f77ed4fb13 Mon Sep 17 00:00:00 2001 From: paulklint Date: Mon, 26 Jan 2026 00:50:27 +0100 Subject: [PATCH 10/10] Create compatibility for building a moduleStatus --- .../src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc index 916f2b3cd..8ef95e620 100644 --- a/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc +++ b/rascal-lsp/src/main/rascal/lsp/lang/rascal/lsp/refactor/Rename.rsc @@ -232,7 +232,7 @@ TModel getConditionallyAugmentedTModel(loc l, set[Define] defs, set[AugmentCompo : r.getConfig().tmodelForLoc(l); public Edits rascalRenameSymbol(loc cursorLoc, list[Tree] cursor, str newName, set[loc] workspaceFolders, PathConfig(loc) getPathConfig) { - ModuleStatus ms = newModuleStatus(); + ModuleStatus ms = moduleStatus({}, {}, (), [], (), [], {}, (), (), (), (), pathConfig(), tconfig()); TModel tmodelForTree(Tree tr) = tmodelForLoc(tr.src.top);