diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/ADTandGrammar.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/ADTandGrammar.rsc index e60eb823db..1f2f356428 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/ADTandGrammar.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/ADTandGrammar.rsc @@ -178,7 +178,7 @@ tuple[bool, TModel, ModuleStatus] addGrammar(MODID moduleId, set[MODID] imports, = getTModelForModule(m, ms); if(!found) { msg = error("Cannot add grammar or tmodel since `` is not found", ms.moduleLocs[moduleId] ? |unknown:///|); - println(msg); // TODO: Just to record this event; this should probably go to a log file + //println(msg); // TODO: Just to record this event; this should probably go to a log file ms.messages[moduleId] ? {} += { msg }; tm1 = tmodel(modelName=qualifiedModuleName, messages=[msg]); return ; diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/Checker.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/Checker.rsc index 8a95b397a5..d3eeda94e3 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/Checker.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/Checker.rsc @@ -552,7 +552,7 @@ bool uptodateTPls(list[loc] candidates, list[str] mnames, PathConfig pcfg){ for(int i <- index(candidates)){ mloc = candidates[i]; = getTPLReadLoc(mnames[i], pcfg); - if(!found || lastModified(mloc) > lastModified(tpl)){ + if(!found || lastModified(mloc) >= lastModified(tpl)){ return false; } } diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/CheckerCommon.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/CheckerCommon.rsc index 592e642e3e..b8f89b6272 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/CheckerCommon.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/CheckerCommon.rsc @@ -225,7 +225,7 @@ bool tplOutdated(MODID moduleId, PathConfig pcfg){ lmMloc = lastModified(mloc); lmTpl = lastModified(tpl); res = !found || lmMloc > lmTpl; - //println("tplOutdated : ; mloc: \> tpl: : lmTpl>, (, )"); + // println("tplOutdated : ; mloc: \> tpl: : lmTpl>, (, )"); return res; } catch _: { return false; diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc index 220ba9e2d2..103f5c28c8 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc @@ -328,10 +328,11 @@ str getModuleNameFromAnyLogical(loc l){ tuple[bool, ModuleStatus] importsAndExtendsAreBinaryCompatible(TModel tm, set[MODID] importsAndExtends, ModuleStatus ms){ moduleName = tm.modelName; physical2logical = invertUnique(tm.logical2physical); - - modRequires = { lg | l <- range(tm.useDef), - physical2logical[l]?, lg := physical2logical[l], - moduleName !:= getModuleNameFromAnyLogical(lg) }; + modRequires = {lg | l <- range(tm.useDef), + l in physical2logical, + lg := physical2logical[l], + moduleName != getModuleNameFromAnyLogical(lg) + }; provided = {}; if(!isEmpty(modRequires)){ for(m <- importsAndExtends){ @@ -342,8 +343,6 @@ tuple[bool, ModuleStatus] importsAndExtendsAreBinaryCompatible(TModel tm, set[MO } } - //println(" requires "); - if(isEmpty(modRequires - provided)){ //println("importsAndExtendsAreBinaryCompatible : satisfied"); return ; diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/BinaryDependencyTests.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/BinaryDependencyTests.rsc index 5bf5c69c70..1cee586e9f 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/BinaryDependencyTests.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/BinaryDependencyTests.rsc @@ -46,6 +46,7 @@ import String; import lang::rascalcore::check::ModuleLocations; import util::FileSystem; import util::SemVer; +import lang::rascalcore::check::tests::StaticTestingUtils; // ---- Utilities for test setup ---------------------------------------------- @@ -99,6 +100,9 @@ str writeModule(str mname, str mtext){ throw "Parse error in "; } +loc getModuleLoc(str mname, Project pd) + = src(pd.name) + ".rsc"; + PathConfig createPathConfig(str pname){ return pathConfig( srcs=[src(pname)], @@ -111,7 +115,9 @@ PathConfig createPathConfig(str pname){ Project addModule(str mname, str mtext, Project pd){ pd.modules[mname] = writeModule(mname, mtext); - writeFile(src(pd.name) + ".rsc", pd.modules[mname]); + mloc = getModuleLoc(mname, pd); + writeFile(mloc, pd.modules[mname]); + assert exists(mloc) : " does not exist after write"; return pd; } @@ -119,14 +125,18 @@ Project changeModule(str mname, str mtext, Project pd){ if(!pd.modules[mname]?) throw "Module does not exist in "; pd.modules[mname] = writeModule(mname, mtext); - writeFile(src(pd.name) + ".rsc", pd.modules[mname]); + mloc = getModuleLoc(mname, pd); + writeFile(mloc, pd.modules[mname]); + assert exists(mloc) : " does not exist after write"; return pd; } Project removeSourceOfModule(str mname, Project pd){ if(!pd.modules[mname]?) throw "Cannot remove non-existing module "; pd.modules = delete(pd.modules, mname); - remove(src(pd.name) + ".rsc", recursive=true); + mloc = getModuleLoc(mname, pd); + remove(mloc, recursive=true); + assert !exists(mloc): " not removed"; return pd; } @@ -533,7 +543,7 @@ test bool incompatibleVersionsOfBinaryLibrary(){ // Important: we do not recompile TP (and thus it will contain the outdated version of IO) - // Update Checks' modification time to make sure it will rechecked + // Update Checks' modification time to make sure it will be rechecked touch(getRascalModuleLocation("Check", core.pcfg)); // Recompile Check and discover the error return checkExpectErrors("Check", ["Review of dependencies, reconfiguration or recompilation needed: binary module `TP` depends (indirectly) on incompatible module(s)"], core.pcfg, remove = [rascal, typepal, core]); diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ChangeScenarioTests.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ChangeScenarioTests.rsc index 00c5b855b5..cef2ace507 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ChangeScenarioTests.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/ChangeScenarioTests.rsc @@ -469,6 +469,29 @@ test bool breakingChange1(){ return expectReChecks(D, ["C", "D"]); } +test bool fixedErrorsDisappearCompact() { + clearMemory(); + pcfg = getDefaultTestingPathConfig(); + + mlocs = writeModules(" + module ParserBase + "); + + assert checkModulesOK(mlocs, pathConfig=pcfg) : "Precondition failed: no errors expected!"; + + // Introduce a type error (import of module that does not exist) + l = writeModule(" + module ParserBase + + import vis::ParseTree; // module does not exist -\> error + + "); + + assert missingModuleInModule(l, pathConfig=pcfg) : "Precondition failed: expected at least one error, but got none!"; + + return true; +} + test bool fixedErrorsDisappear() { // ht @toinehartman clearMemory(); pcfg = getReleasedStandardLibraryTestingPathConfig(); diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/PackagerTests.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/PackagerTests.rsc index 62902a8459..ee153433ed 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/PackagerTests.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/PackagerTests.rsc @@ -48,7 +48,7 @@ private void runChecker(PathConfig pcfg, list[str] mnames) { test bool packagerRewritesTModelsCorrectly () { println("**** Checking List"); - tplRoot = |memory:///|; + tplRoot = |memory://packager-test/|; originalBin = tplRoot + "rascal-lib"; rewrittenBin = tplRoot + "rascal-lib-rewritten"; rascalLibPcfg = diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/StaticTestingUtils.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/StaticTestingUtils.rsc index 85c1d4e8a8..8393190b56 100644 --- a/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/StaticTestingUtils.rsc +++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/tests/StaticTestingUtils.rsc @@ -42,6 +42,7 @@ import Relation; import Set; import util::Reflective; import ParseTree; +import util::FileSystem; import lang::rascalcore::check::RascalConfig; import lang::rascalcore::check::Checker; @@ -104,6 +105,19 @@ void removeModule(str mname){ remove(pcfg.generatedResources + ".tpl"); } +void printModules(){ + println("\<\<\<\<"); + for(f <- find(testRoot, "rsc")){ + println(" : + '"); + } + for(f <- find(testRoot, "tpl")){ + println(": "); + } + println("\>\>\>\>"); +} + + set[Message] getErrorMessages(ModuleStatus r) = { m | m <- getAllMessages(r), m is error }; diff --git a/src/org/rascalmpl/uri/libraries/MemoryResolver.java b/src/org/rascalmpl/uri/libraries/MemoryResolver.java index c174c9ae37..3f14739f3e 100644 --- a/src/org/rascalmpl/uri/libraries/MemoryResolver.java +++ b/src/org/rascalmpl/uri/libraries/MemoryResolver.java @@ -25,6 +25,8 @@ import java.nio.file.NoSuchFileException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; + import org.checkerframework.checker.nullness.qual.Nullable; import org.rascalmpl.uri.FileAttributes; import org.rascalmpl.uri.ISourceLocationInputOutput; @@ -62,8 +64,29 @@ */ public class MemoryResolver implements ISourceLocationInputOutput { + private static class MemoryEntry extends FSEntry { + /** keep track of the timestamp across entries */ + private static final AtomicLong now = new AtomicLong(System.currentTimeMillis()); + + /** + * Every time we're called, we get a new timestamp, to make sure file written at roughly the same + * time don't get the same modification timestamp + * @return + */ + private static long timestamp() { + return now.accumulateAndGet(System.currentTimeMillis(), (now, prev) -> { + if (now > prev) { + return now; + } + if (now == prev) { + return now + 1; + } + // else : prev > now + return prev + 1; + }); + } private final @Nullable byte[] contents; public MemoryEntry() { @@ -71,7 +94,11 @@ public MemoryEntry() { } public MemoryEntry(@Nullable byte[] contents) { - this(System.currentTimeMillis(), System.currentTimeMillis(), contents); + this(timestamp(), contents); + } + + private MemoryEntry(long created, @Nullable byte[] contents) { + this(created, created, contents); } public MemoryEntry(long created, long lastModified) { @@ -83,19 +110,11 @@ public MemoryEntry(long created, long lastModified, @Nullable byte[] contents) { } public MemoryEntry newContents(byte[] newContents) { - long newTimestamp = System.currentTimeMillis(); - if (newTimestamp <= getLastModified()) { - newTimestamp = getLastModified() + 1; - } - return new MemoryEntry(getCreated(), newTimestamp, newContents); + return new MemoryEntry(getCreated(), timestamp(), newContents); } public MemoryEntry copy() { - long newTimestamp = System.currentTimeMillis(); - if (newTimestamp <= getLastModified()) { - newTimestamp = getLastModified() + 1; - } - return new MemoryEntry(newTimestamp, newTimestamp, contents); + return new MemoryEntry(timestamp(), contents); } }