diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/Checker.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/Checker.rsc index a6363b66e7c..9e2d5b2b603 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/Checker.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/Checker.rsc @@ -299,6 +299,14 @@ ModuleStatus rascalTModelForLocs( // } = rascalTModelComponent(component, ms); + + // Convert `tm.facts` and `tm.defines` to a more efficient + // representation for later use + map[loc, AType] facts = tm.facts; + rel[str, AType] factsByPath = { | loc l <- facts}; + Defines defines = tm.defines; + rel[str, Define] definesByPath = { | Define d <- defines}; + // moduleScopes += getModuleScopes(tm); map[str,TModel] tmodels_for_component = (); map[MODID,set[MODID]] m_imports = (); @@ -328,13 +336,13 @@ ModuleStatus rascalTModelForLocs( imsgs += error("Rascal TPL version error for ``, no source found", imod.src); } if(inameId notin usedModules){ - if(iname == "ParseTree" && implicitlyUsesParseTree(ms.moduleLocs[m].path, tm)){ + if(iname == "ParseTree" && implicitlyUsesParseTree(ms.moduleLocs[m].path, factsByPath)){ continue check_imports; } - if(ms.moduleLocs[inameId]? && ms.moduleLocs[m]? && implicitlyUsesLayoutOrLexical(ms.moduleLocs[m].path, ms.moduleLocs[inameId].path, tm)){ + if(ms.moduleLocs[inameId]? && ms.moduleLocs[m]? && implicitlyUsesLayoutOrLexical(ms.moduleLocs[m].path, ms.moduleLocs[inameId].path, factsByPath)){ continue check_imports; } - if(ms.moduleLocs[inameId]? && ms.moduleLocs[m]? && usesOrExtendsADT(ms.moduleLocs[m].path, ms.moduleLocs[inameId].path, tm)){ + if(ms.moduleLocs[inameId]? && ms.moduleLocs[m]? && usesOrExtendsADT(ms.moduleLocs[m].path, ms.moduleLocs[inameId].path, factsByPath, definesByPath)){ continue check_imports; } if((inameId in component || hasProperty(inameId, ms, checked())) && hasNotProperty(inameId, ms, rsc_not_found())){ @@ -401,20 +409,20 @@ ModuleStatus rascalTModelForLocs( return clearTModelCache(ms); } -bool implicitlyUsesParseTree(str modulePath, TModel tm){ - return any(loc l <- tm.facts, l.path == modulePath, areified(_) <- tm.facts[l]); +bool implicitlyUsesParseTree(str modulePath, rel[str, AType] factsByPath){ + return any(areified(_) <- factsByPath[modulePath]); } -bool implicitlyUsesLayoutOrLexical(str modulePath, str importPath, TModel tm){ - return any(loc l <- tm.facts, l.path == importPath, aadt(_,_,sr) := tm.facts[l], sr in {layoutSyntax(), lexicalSyntax()}) - && any(loc l <- tm.facts, l.path == modulePath, aadt(_,_,contextFreeSyntax()) := tm.facts[l]); +bool implicitlyUsesLayoutOrLexical(str modulePath, str importPath, rel[str, AType] factsByPath){ + return any(aadt(_,_,sr) <- factsByPath[importPath], sr in {layoutSyntax(), lexicalSyntax()}) + && any(aadt(_,_,contextFreeSyntax()) <- factsByPath[modulePath]); } -bool usesOrExtendsADT(str modulePath, str importPath, TModel tm){ - usedADTs = { unset(tm.facts[l], "alabel") | loc l <- tm.facts, l.path == modulePath, aadt(_,_,_) := tm.facts[l] }; - definedADTs = { unset(the_adt, "alabel") | Define d <- tm.defines, d.defined.path == modulePath, defType(the_adt:aadt(_,_,_)) := d.defInfo }; +bool usesOrExtendsADT(str modulePath, str importPath, rel[str, AType] factsByPath, rel[str, Define] definesByPath){ + usedADTs = { unset(the_adt, "alabel") | the_adt:aadt(_,_,_) <- factsByPath[modulePath] }; + definedADTs = { unset(the_adt, "alabel") | Define d <- definesByPath[modulePath], defType(the_adt:aadt(_,_,_)) := d.defInfo }; usedOrDefinedADTs = usedADTs + definedADTs; - res = any(loc l <- tm.facts, l.path == importPath, the_adt:aadt(_,_,_) := tm.facts[l], unset(the_adt, "alabel") in usedOrDefinedADTs); + res = any(the_adt:aadt(_,_,_) <- factsByPath[importPath], unset(the_adt, "alabel") in usedOrDefinedADTs); return res; } diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc index 6b39268e7ef..881a6cf846b 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc @@ -420,17 +420,20 @@ ModuleStatus doSaveModule(set[MODID] component, map[MODID,set[MODID]] m_imports, component = { m | m <- component, hasNotProperty(m, ms, ModuleProperty::ignored()) }; if(isEmpty(component)) return ms; - //println("doSaveModule: , , , "); - component_scopes = component; //{ getModuleScope(mid, moduleScopes, pcfg) | MODID mid <- component }; + set[MODID] componentScopes = component; + map[str, MODID] componentScopesByUri = (); set[MODID] filteredModuleScopes = {}; + map[str, MODID] filteredModuleScopesByUri = (); loc2moduleName = invertUnique(ms.moduleLocs); bool isContainedInComponentScopes(loc inner, map[loc,loc] m){ - return any(cs <- component_scopes, isContainedIn(inner, cs, m)); + inner = m[inner] ? inner; + return inner.uri in componentScopesByUri && isContainedIn(inner, componentScopesByUri[inner.uri]); }; bool isContainedInFilteredModuleScopes(loc inner, map[loc,loc] m){ - return any(cs <- filteredModuleScopes, isContainedIn(inner, cs, m)); + inner = m[inner] ? inner; + return inner.uri in filteredModuleScopesByUri && isContainedIn(inner, filteredModuleScopesByUri[inner.uri]); }; for(currentModule <- component){ @@ -443,9 +446,20 @@ ModuleStatus doSaveModule(set[MODID] component, map[MODID,set[MODID]] m_imports, bom = makeBom(currentModule, ms); + // Lookup fields only once to save interpreter time (significant) + paths = tm.paths; + facts = tm.facts; + specializedFacts = tm.specializedFacts; + useDef = tm.useDef; + logical2physical = tm.logical2physical; + definitions = tm.definitions; + + componentScopesByUri = (s.uri: s | loc s <- componentScopes, loc s := logical2physical[s] ? s); + extendedModuleScopes = {m | MODID m <- extends, hasProperty(m, ms, checked())}; - extendedModuleScopes += {*tm.paths[ems,importPath()] | MODID ems <- extendedModuleScopes}; // add imports of extended modules + extendedModuleScopes += {*paths[ems,importPath()] | MODID ems <- extendedModuleScopes}; // add imports of extended modules filteredModuleScopes = {m | MODID m <- (currentModule + imports), hasProperty(m, ms, checked())} + extendedModuleScopes; + filteredModuleScopesByUri = (m.uri: m | loc m <- filteredModuleScopes, loc m := logical2physical[m] ? m); TModel m1 = tmodel(); m1.version = getCurrentTplVersion(); @@ -453,22 +467,15 @@ ModuleStatus doSaveModule(set[MODID] component, map[MODID,set[MODID]] m_imports, m1.modelName = moduleId2moduleName(currentModule); m1.moduleLocs = (m1.modelName : currentModule); - m1.facts = (key : tm.facts[key] | key <- tm.facts, isContainedInFilteredModuleScopes(key, tm.logical2physical)); + m1.facts = (key : facts[key] | key <- facts, isContainedInFilteredModuleScopes(key, logical2physical)); - m1.specializedFacts = (key : tm.specializedFacts[key] | key <- tm.specializedFacts, isContainedInComponentScopes(key, tm.logical2physical), any(fms <- filteredModuleScopes, isContainedIn(key, fms))); + m1.specializedFacts = (key : specializedFacts[key] | key <- specializedFacts, isContainedInComponentScopes(key, logical2physical), isContainedInFilteredModuleScopes(key, logical2physical)); m1.facts += m1.specializedFacts; - m1.messages = [msg | msg <- tm.messages, isContainedIn(msg.at, currentModule, tm.logical2physical)]; + m1.messages = [msg | msg <- tm.messages, isContainedIn(msg.at, currentModule, logical2physical)]; ms.messages[currentModule] = toSet(m1.messages); - filteredModuleScopePaths = {ml.path |loc ml <- filteredModuleScopes}; m1.scopes = tm.scopes; - // m1.scopes - // = ( inner : tm.scopes[inner] - // | loc inner <- tm.scopes, - // inner.path in filteredModuleScopePaths, - // (tm.scopes[inner] == |global-scope:///| || isContainedInComponentScopes(inner, tm.logical2physical)) - // ); m1.store = (key_bom : bom); @@ -480,23 +487,23 @@ ModuleStatus doSaveModule(set[MODID] component, map[MODID,set[MODID]] m_imports, m1.store[key_common_keyword_fields] = tm.store[key_common_keyword_fields] ? []; - m1.paths = { tup | tuple[MODID from, PathRole pathRole, MODID to] tup <- tm.paths, tup.from == currentModule || tup.from in filteredModuleScopes /*|| tup.from in filteredModuleScopePaths*/ }; + m1.paths = { tup | tuple[MODID from, PathRole pathRole, MODID to] tup <- paths, tup.from == currentModule || tup.from in filteredModuleScopes }; keepRoles = variableRoles + keepInTModelRoles; m1.useDef = { - | <- tm.useDef, - isContainedIn(u, currentModule, tm.logical2physical) - || (tm.definitions[d]? && tm.definitions[d].idRole in keepRoles) + | <- useDef, + isContainedIn(u, currentModule, logical2physical) + || (definitions[d]? && definitions[d].idRole in keepRoles) }; // Filter model for current module and replace functions in defType by their defined type defs = for(tup: <- tm.defines){ - if( ( idRole in variableRoles ? ( isContainedInComponentScopes(defined, tm.logical2physical) + if( ( idRole in variableRoles ? ( isContainedInComponentScopes(defined, logical2physical) ) : ( idRole in keepInTModelRoles - && ( isContainedInComponentScopes(defined, tm.logical2physical) - || isContainedInFilteredModuleScopes(defined, tm.logical2physical) + && ( isContainedInComponentScopes(defined, logical2physical) + || isContainedInFilteredModuleScopes(defined, logical2physical) ) ) ) @@ -511,14 +518,14 @@ ModuleStatus doSaveModule(set[MODID] component, map[MODID,set[MODID]] m_imports, m1.define2id = tm.define2id; // Remove default expressions and fragments + // (Relatively expensive: can take >50% of the execution time of this function) m1 = visit(m1) { case kwField(AType atype, str fieldName, str definingModule, Expression _defaultExp) => kwField(atype, fieldName, definingModule) case loc l : if(!isEmpty(l.fragment)) insert l[fragment=""]; }; - m1.logical2physical = tm.logical2physical; + m1.logical2physical = logical2physical; ms = deleteProperty(currentModule, ms, tpl_saved()); ms = addTModel(currentModule, m1, ms); - // println("TModel for :"); iprintln(m1); } return ms; } \ No newline at end of file diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/RascalConfig.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/RascalConfig.rsc index e64fb92c351..e02a5287979 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/RascalConfig.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/RascalConfig.rsc @@ -323,23 +323,25 @@ bool isOverloadedFunction(loc fun, map[loc,Define] definitions, map[loc, AType] } bool rascalReportUnused(loc def, TModel tm){ + return rascalFilterUnused([def], tm) == [def]; +} + +list[loc] rascalFilterUnused(list[loc] defs, TModel tm) { config = tm.config; - if(!config.warnUnused) return false; + if(!config.warnUnused) return []; + // Lookup fields only once to save interpreter time (significant) + warnUnusedFormals = config.warnUnusedFormals; + moduleLocs = tm.moduleLocs; + modelName = tm.modelName; + logical2physical = tm.logical2physical; definitions = tm.definitions; - - if(!definitions[def]? || !tm.moduleLocs[tm.modelName]?) return false; - - if(!isContainedIn(definitions[def].defined, tm.moduleLocs[tm.modelName], tm.logical2physical)){ - return false; - } - scopes = tm.scopes; facts = tm.facts; bool reportFormal(Define define){ - if(!config.warnUnusedFormals || isWildCard(define.id[0])) return false; - container = tm.definitions[findContainer(def, definitions, scopes)]; + if(!warnUnusedFormals || isWildCard(define.id[0])) return false; + container = definitions[findContainer(define.defined, definitions, scopes)]; if(container.idRole == functionId()){ if(isOverloadedFunction(container.defined, definitions, facts)) return false; return "java" notin container.defInfo.modifiers; @@ -347,8 +349,8 @@ bool rascalReportUnused(loc def, TModel tm){ return false; } - define = definitions[def]; - try { + bool filterFormal(loc def) { + define = definitions[def]; switch(define.idRole){ case moduleId(): return false; case dataId(): return false; @@ -383,9 +385,25 @@ bool rascalReportUnused(loc def, TModel tm){ case layoutId(): return false; case keywordId(): return false; } - } catch NoSuchKey(_): return false; + return true; + } + + bool tryFilterFormal(loc def) { + try { + return filterFormal(def); + } catch NoSuchKey(_): { + return false; + } + } - return true; + if (modelName in moduleLocs) { + moduleLoc = moduleLocs[modelName]; + moduleLoc = logical2physical[moduleLoc] ? moduleLoc; + // Assumption: `logical2physical` has already been applied to each `def` + return [def | loc def <- defs, isContainedIn(def, moduleLoc), tryFilterFormal(def)]; + } else { + return []; + } } // Extend the path relation by @@ -663,6 +681,7 @@ RascalCompilerConfig rascalCompilerConfig(PathConfig pcfg, preSolver = rascalPreSolver, postSolver = rascalPostSolver, reportUnused = rascalReportUnused, + filterUnused = rascalFilterUnused, createLogicalLoc = rascalCreateLogicalLoc, similarNames = rascalSimilarNames ); diff --git a/src/org/rascalmpl/interpreter/env/ModuleEnvironment.java b/src/org/rascalmpl/interpreter/env/ModuleEnvironment.java index 1cbca8745ae..be5f4fb0bd0 100644 --- a/src/org/rascalmpl/interpreter/env/ModuleEnvironment.java +++ b/src/org/rascalmpl/interpreter/env/ModuleEnvironment.java @@ -90,6 +90,7 @@ public class ModuleEnvironment extends Environment { private Map resourceImporters; private Map> cachedGeneralKeywordParameters; private Map> cachedPublicFunctions; + private List cachedImportedModulesResolved; private static final TypeFactory TF = TypeFactory.getInstance(); @@ -109,6 +110,7 @@ public ModuleEnvironment(String name, GlobalEnvironment heap) { this.resourceImporters = new HashMap(); this.cachedGeneralKeywordParameters = null; this.cachedPublicFunctions = null; + this.cachedImportedModulesResolved = null; } @Override @@ -127,12 +129,14 @@ public void reset() { this.generalKeywordParameters = new HashMap<>(); this.cachedGeneralKeywordParameters = null; this.cachedPublicFunctions = null; + this.cachedImportedModulesResolved = null; } public void clearLookupCaches() { importedModules.replaceAll((k, v) -> Optional.empty()); cachedGeneralKeywordParameters = null; cachedPublicFunctions = null; + cachedImportedModulesResolved = null; } /** @@ -382,12 +386,14 @@ public void addImport(String name, ModuleEnvironment env) { typeStore.importStore(env.typeStore); this.cachedGeneralKeywordParameters = null; this.cachedPublicFunctions = null; + this.cachedImportedModulesResolved = null; } void removeModule(String name) { importedModules.computeIfPresent(name, (k, v) -> Optional.empty()); this.cachedGeneralKeywordParameters = null; this.cachedPublicFunctions = null; + this.cachedImportedModulesResolved = null; } public void addExtend(String name) { @@ -397,6 +403,7 @@ public void addExtend(String name) { extended.add(name); this.cachedGeneralKeywordParameters = null; this.cachedPublicFunctions = null; + this.cachedImportedModulesResolved = null; } public List getTests() { @@ -453,6 +460,7 @@ public void unImport(String moduleName) { } cachedGeneralKeywordParameters = null; cachedPublicFunctions = null; + cachedImportedModulesResolved = null; } public void unExtend(String moduleName) { @@ -522,7 +530,7 @@ public void storeVariable(String name, Result value) { super.storeVariable(name, value); } else { - for (ModuleEnvironment module : importedModulesResolved) { + for (ModuleEnvironment module : getImportedModulesResolved()) { result = module.getLocalPublicVariable(name); if (result != null) { @@ -543,7 +551,7 @@ public org.rascalmpl.interpreter.result.Result getSimpleVariable(String return var; } - for (ModuleEnvironment mod : importedModulesResolved) { + for (ModuleEnvironment mod : getImportedModulesResolved()) { if (mod != null) { var = mod.getLocalPublicVariable(name); @@ -570,7 +578,7 @@ protected Map> getVariableDefiningEnvironment(String name) } } - for (ModuleEnvironment mod : importedModulesResolved) { + for (ModuleEnvironment mod : getImportedModulesResolved()) { Result r = null; if (mod != null && mod.variableEnvironment != null) r = mod.variableEnvironment.get(name); @@ -592,7 +600,7 @@ private List lookupFunctionsNoCache(String name) { var result = new ArrayList(); super.getAllFunctions(name, result); - for (ModuleEnvironment mod : importedModulesResolved) { + for (ModuleEnvironment mod : getImportedModulesResolved()) { if (mod != null) { mod.getLocalPublicFunctions(name, result); } @@ -783,7 +791,7 @@ public Set lookupGenericKeywordParameters(Type adt) { result.add(new GenericKeywordParameters(this, list, getStore().getKeywordParameters(adt))); } - for (ModuleEnvironment mod : importedModulesResolved) { + for (ModuleEnvironment mod : getImportedModulesResolved()) { list = mod.generalKeywordParameters.get(adt); if (list != null) { @@ -884,24 +892,20 @@ public ModuleEnvironment getImport(String moduleName) { return result.get(); } - private Iterable importedModulesResolved = - () -> new Iterator() { - Iterator>> iterator = importedModules.entrySet().iterator(); - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - @Override - public ModuleEnvironment next() { - var entry = iterator.next(); + private List getImportedModulesResolved() { + if (cachedImportedModulesResolved == null) { + cachedImportedModulesResolved = new ArrayList<>(); + for (var entry : importedModules.entrySet()) { var result = entry.getValue(); if (result.isEmpty()) { result = Optional.ofNullable(heap.getModule(entry.getKey())); entry.setValue(result); } - return result.orElse(null); + cachedImportedModulesResolved.add(result.orElse(null)); } - }; + } + return cachedImportedModulesResolved; + } @Override public void storeVariable(QualifiedName name, Result result) { @@ -940,7 +944,7 @@ public Type lookupConcreteSyntaxType(String name) { Type type = concreteSyntaxTypes.get(name); if (type == null) { - for (ModuleEnvironment mod : importedModulesResolved) { + for (ModuleEnvironment mod : getImportedModulesResolved()) { if (mod == null) { continue; @@ -1100,7 +1104,7 @@ protected Environment getVariableFlagsEnvironment(String name) { return env; } - for (ModuleEnvironment mod : importedModulesResolved) { + for (ModuleEnvironment mod : getImportedModulesResolved()) { if(mod == null) { throw new RuntimeException("getFlagsEnvironment"); } @@ -1122,7 +1126,7 @@ protected Environment getFunctionFlagsEnvironment(String name) { return env; } - for (ModuleEnvironment mod : importedModulesResolved) { + for (ModuleEnvironment mod : getImportedModulesResolved()) { if(mod == null) { throw new RuntimeException("getFlagsEnvironment"); }