ResolveResult (@NotNull RuntimeModuleId moduleId, @NotNull Map<RuntimeModuleId, RuntimeModuleDescriptorImpl> dependencyPath) { ResolveResult cached = myResolveResults.get(moduleId); if (cached != null) return cached; RawRuntimeModuleDescriptor rawDescriptor = getRawDescriptors().get(moduleId.getStringId()); if (rawDescriptor == null) { List<RuntimeModuleId> failedPath = new ArrayList<>(dependencyPath.size() + 1); failedPath.addAll(dependencyPath.keySet()); failedPath.add(moduleId); return new FailedResolveResult(failedPath); } List<String> rawDependencies = rawDescriptor.getDependencies(); List<RuntimeModuleDescriptor> resolvedDependencies = new ArrayList<>(rawDependencies.size()); RuntimeModuleDescriptorImpl descriptor = new RuntimeModuleDescriptorImpl(moduleId, myBasePath, rawDescriptor.getResourcePaths(), resolvedDependencies); dependencyPath.put(moduleId, descriptor); for (String dependency : rawDependencies) { RuntimeModuleId dependencyId = myInternedModuleIds.computeIfAbsent(dependency, RuntimeModuleId::raw); RuntimeModuleDescriptor circularDependency = dependencyPath.get(dependencyId); if (circularDependency != null) { //the circularDependency instance isn't fully constructed, but it's ok given that RuntimeModuleDescriptorImpl's constructor just stores the passed values resolvedDependencies.add(circularDependency); continue; } ResolveResult result = resolveModule(dependencyId, dependencyPath); RuntimeModuleDescriptor module = result.getResolvedModule(); if (module != null) { resolvedDependencies.add(module); } else { return result; } } dependencyPath.remove(moduleId); SuccessfulResolveResult result = new SuccessfulResolveResult(descriptor); myResolveResults.put(moduleId, result); return result; }