public static void cloneTypes(Iterable <TypeInfo> types, Library targetTypeSystem) { var t0 = System.nanoTime(); foreach (var type in types) { defineType(type, targetTypeSystem, null); } foreach (var type in types) { declareType(type, targetTypeSystem, (TypeBuilder)targetTypeSystem.getType(type.FullName), new Scope <String, TypeInfo>()); } Environment.trace(targetTypeSystem, types.count() + " types cloned in " + ((System.nanoTime() - t0) / 1e6) + "ms"); }
static void declareGenericTypeBindings(GenericParameterBindings genericsScope, Iterable <TypeInfo> keys, Iterable <TypeInfo> values) { if (keys.count() != values.count()) { throw new IllegalStateException(); } var it1 = keys.iterator(); var it2 = values.iterator(); while (it1.hasNext()) { var t1 = it1.next(); var t2 = it2.next(); if (t1.IsGenericParameter) { genericsScope.declareBinding(t1, t2); } } }
private static String[] getTypeNames(Iterable<TypeInfo> types) { if (types.any()) { String[] result = new String[types.count()]; int i = 0; foreach (var t in types) { result[i++] = t.FullName; } return result; } else { return null; } }
private void replaceCref(Element element, bool exception, Iterable <MemberInfo> members, String suffix, String arguments) { if (members.count() > 1 && !members.all(p => p.MemberKind == MemberKind.Method)) { context.addWarning(CompileErrorId.UnresolvedCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); return; } var member = members.first(); switch (member.MemberKind) { case Type: replaceCref(element, exception, member.Type, suffix, arguments); break; case Field: if (exception) { context.addWarning(CompileErrorId.ExpectedExceptionInCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); return; } if (suffix != null || arguments != null) { context.addWarning(CompileErrorId.UnresolvedCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); return; } element.setAttribute("cref", getIdString(member.Field)); break; case Property: if (exception) { context.addWarning(CompileErrorId.ExpectedExceptionInCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); return; } if (suffix != null || arguments != null) { context.addWarning(CompileErrorId.UnresolvedCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); return; } element.setAttribute("cref", getIdString(member.GetAccessor ?? member.SetAccessor)); break; case Method: if (!exception && suffix == null) { if (arguments == null && members.count() == 1) { element.setAttribute("cref", getIdString(member.Method)); return; } else if (arguments != null && arguments.endsWith(")")) { var args = new ArrayList <TypeInfo>(); if (arguments.length() > 2) { arguments = arguments.substring(1, arguments.length() - 1); int idx; while ((idx = arguments.indexOf(',')) != -1) { var name = arguments.substring(0, idx); arguments = arguments.substring(idx + 1); var type = getType(name); if (type == null) { goto failed; } args.add(type); } if (arguments.length() == 0) { goto failed; } var type = getType(arguments); if (type == null) { goto failed; } args.add(type); } foreach (var m in members) { if (m.Method.Parameters.select(p => p.Type).sequenceEqual(args)) { element.setAttribute("cref", getIdString(m.Method)); return; } } } } failed: context.addWarning(CompileErrorId.UnresolvedCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); break; default: break; } }
private void replaceCref(Element element, bool exception, Iterable<MemberInfo> members, String suffix, String arguments) { if (members.count() > 1 && !members.all(p => p.MemberKind == MemberKind.Method)) { context.addWarning(CompileErrorId.UnresolvedCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); return; } var member = members.first(); switch (member.MemberKind) { case Type: replaceCref(element, exception, member.Type, suffix, arguments); break; case Field: if (exception) { context.addWarning(CompileErrorId.ExpectedExceptionInCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); return; } if (suffix != null || arguments != null) { context.addWarning(CompileErrorId.UnresolvedCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); return; } element.setAttribute("cref", getIdString(member.Field)); break; case Property: if (exception) { context.addWarning(CompileErrorId.ExpectedExceptionInCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); return; } if (suffix != null || arguments != null) { context.addWarning(CompileErrorId.UnresolvedCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); return; } element.setAttribute("cref", getIdString(member.GetAccessor ?? member.SetAccessor)); break; case Method: if (!exception && suffix == null) { if (arguments == null && members.count() == 1) { element.setAttribute("cref", getIdString(member.Method)); return; } else if (arguments != null && arguments.endsWith(")")) { var args = new ArrayList<TypeInfo>(); if (arguments.length() > 2) { arguments = arguments.substring(1, arguments.length() - 1); int idx; while ((idx = arguments.indexOf(',')) != -1) { var name = arguments.substring(0, idx); arguments = arguments.substring(idx + 1); var type = getType(name); if (type == null) { goto failed; } args.add(type); } if (arguments.length() == 0) { goto failed; } var type = getType(arguments); if (type == null) { goto failed; } args.add(type); } foreach (var m in members) { if (m.Method.Parameters.select(p => p.Type).sequenceEqual(args)) { element.setAttribute("cref", getIdString(m.Method)); return; } } } } failed: context.addWarning(CompileErrorId.UnresolvedCref, node, element.getAttribute("cref")); element.setAttribute("cref", "!" + element.getAttribute("cref")); break; default: break; } }
private static Iterable <MemberInfo> getMembers(Library typeSystem, TypeInfo type, String name, Iterable <TypeInfo> typeArguments, bool useCache, LookupContext context) { var nTypeArgs = typeArguments.count(); foreach (var mi in (useCache) ? getCachedMembers(typeSystem, type, name) : getMembers(typeSystem, type, name)) { switch (mi.MemberKind) { case Field: if (nTypeArgs == 0 && context.lookupField) { context.lookupField = false; yield return(mi); } break; case Property: if (nTypeArgs == 0 && context.lookupProperty) { context.lookupProperty = false; yield return(mi); } break; case Method: if (nTypeArgs > 0) { if (nTypeArgs == mi.Method.GenericArguments.count()) { yield return(MemberInfo.getInfo(typeSystem.getGenericMethod(mi.Method, typeArguments))); } } else { yield return(mi); } break; case Type: if (context.lookupClass) { context.lookupClass = false; if (nTypeArgs > 0) { if (nTypeArgs == mi.Type.GenericArguments.count()) { yield return(mi); } } else { if (mi.MemberKind == MemberKind.Type && mi.Type.GenericArguments.count() > 0) { mi = MemberInfo.getInfo(mi.Type.RawType); } yield return(mi); } } break; } } }
private SourceCompilerResults compileCore(IProgressMonitor monitor) { var t0 = System.nanoTime(); var results = new SourceCompilerResults(); var hasErrors = false; var errorManager = new CodeErrorManager(); var allFiles = parameters.AllFiles; Iterable <IFile> filesToCompile = null; try { monitor.beginTask("", 11); var deletedFiles = parameters.FilesToCompile .select(p => allFiles.getResource(p)) .where (p => p == null || !p.exists()) .select(p => allFiles.getProjectRelativeName(p)).toSet(); var typesToCopy = Query.empty <TypeInfo>(); // Get the files to compile if (parameters.FullBuild) { filesToCompile = allFiles.getAllResources().where (p => p.exists()).toList(); } else { bool filteringDone = false; var referencingFiles = parameters.getDependencyInfo().getAllReferencingFiles(parameters.getFilesToCompile()); if (parameters.ProgressiveBuild && deletedFiles.isEmpty()) { var referencedFiles = parameters.getDependencyInfo().getAllReferencedFiles(parameters.getFilesToCompile()); referencedFiles = referencedFiles.except(parameters.getFilesToCompile()); referencedFiles = referencedFiles.intersect(referencingFiles); // Progressive build only if referenced and referencing files do not intersect if (!referencedFiles.any()) { filesToCompile = parameters.FilesToCompile.select(p => allFiles.getResource(p)).where (p => p.exists()).toList(); filteringDone = true; } } if (!filteringDone) { // Incremental build with dependencies filesToCompile = referencingFiles.select(p => allFiles.getResource(p)).where (p => p.exists()).toList(); } var filesToKeep = allFiles.getAllProjectRelativeNames().except(referencingFiles); typesToCopy = filesToKeep.selectMany(p => parameters.DependencyInfo.getFileContents(p)) .where (p => p.indexOf('$') == -1).select(p => parameters.TypeSystem.getType(p)); Environment.trace(this, "keeping " + filesToKeep.count() + " files"); Environment.trace(this, "ignoring " + (allFiles.getAllResources().count() - filesToCompile.count() - filesToKeep.count()) + " files"); } Environment.trace(this, "compiling " + filesToCompile.count() + " files"); monitor.worked(1); if (monitor.isCanceled()) { throw new InterruptedException(); } var compilationUnits = new HashMap <String, CompilationUnitNode>(); // Parsing foreach (var file in filesToCompile) { var text = getText(file); if (text != null) { parse(file, text, errorManager, compilationUnits); } } monitor.worked(1); if (monitor.isCanceled()) { throw new InterruptedException(); } // Compiling var t1 = System.nanoTime(); var typeSystem = new Library(parameters.ClassPath); JvmTypeSystemHelper.cloneTypes(typesToCopy, typeSystem); var annotatedTypeSystem = new Library(new[] { Environment.getLibraryPath("stabal.jar") }, typeSystem); var cparams = new CompilerParameters(); cparams.TypeSystem = typeSystem; cparams.AnnotatedTypeSystem = annotatedTypeSystem; cparams.GenerateClassFiles = parameters.GenerateClassFiles; cparams.ProgressTracker = new CompilationProgressTracker(monitor); var cunits = compilationUnits.values().toArray(new CompilationUnitNode[compilationUnits.size()]); var cresults = new StabCompiler().compileFromCompilationUnits(cparams, cunits); Environment.trace(this, "compilation of " + sizeof(cunits) + " files done in " + ((System.nanoTime() - t1) / 1e6) + "ms"); foreach (var error in cresults.Errors) { if (error.Level == 0) { hasErrors = true; } results.CodeErrors.add(error); Environment.trace(this, "error (" + error.Line + ", " + error.Column + ") " + error.Filename + ": " + error.Message); } if (!hasErrors) { var dependencyInfo = new DependencyInfo(); results.DependencyInfo = dependencyInfo; var allTypes = new HashSet <String>(); // Copy informations from unbuilt files if (parameters.DependencyInfo != null) { var unbuiltFiles = allFiles.getAllProjectRelativeNames(); unbuiltFiles = unbuiltFiles.except(filesToCompile.select(p => allFiles.getProjectRelativeName(p))); unbuiltFiles = unbuiltFiles.except(deletedFiles); foreach (var file in unbuiltFiles) { foreach (var type in parameters.DependencyInfo.getFileContents(file)) { allTypes.add(type); dependencyInfo.addFileToTypeRelation(file, type); foreach (var refType in parameters.DependencyInfo.getReferencedTypes(type)) { dependencyInfo.addTypeToTypeRelation(type, refType); } } } } // Collect the types and update the dependencies. var typeMembers = new HashMap <IFile, Iterable <TypeMemberNode> >(); foreach (var file in filesToCompile) { var fileName = allFiles.getProjectRelativeName(file); var compilationUnit = compilationUnits[fileName]; if (compilationUnit == null) { continue; } var members = SyntaxTreeHelper.getTypeMembers(compilationUnit); typeMembers.put(file, members); foreach (var member in members) { var typeName = member.getUserData(typeof(TypeInfo)).FullName; dependencyInfo.addFileToTypeRelation(fileName, typeName); allTypes.add(typeName); } } if (parameters.DependencyInfo != null) { // Copy the types ignored by this compilation var missingTypes = new HashSet <TypeInfo>(); foreach (var t in allTypes.where (p => p.indexOf('$') == -1 && !typeSystem.typeExists(p))) { if (hasErrors = !parameters.DependencyInfo.getReferencedTypes(t).all(p => allTypes.contains(p))) { Environment.trace(this, "Incremental build failed: a type was deleted"); break; } missingTypes.add(parameters.TypeSystem.getType(t)); } if (!hasErrors) { JvmTypeSystemHelper.cloneTypes(missingTypes, typeSystem); } } if (!hasErrors) { // Compute the dependencies in the compiled files foreach (var member in filesToCompile.select(p => typeMembers[p]).where (p => p != null).selectMany(p => p)) { foreach (var t in SyntaxTreeHelper.getTypeMemberDependencies(member) .intersect(allTypes.select(p => JvmTypeSystemHelper.getType(typeSystem, p)))) { dependencyInfo.addTypeToTypeRelation(member.getUserData(typeof(TypeInfo)).FullName, t.FullName); } } results.TypeSystem = typeSystem; results.AnnotatedTypeSystem = annotatedTypeSystem; foreach (var e in compilationUnits.entrySet()) { results.CompilationUnits[e.Key] = e.Value; } foreach (var e in cresults.ClassFiles.entrySet()) { results.ClassFiles[e.Key] = e.Value; } } } monitor.worked(1); } catch (CodeErrorException e) { monitor.worked(10); } catch (TypeLoadException e) { results.MissingType = e.TypeName; hasErrors = true; monitor.worked(6); } finally { monitor.done(); } foreach (var file in filesToCompile) { results.CompiledFiles.add(allFiles.getProjectRelativeName(file)); } foreach (var error in errorManager.Errors) { if (error.Level == 0) { hasErrors = true; } results.CodeErrors.add(error); Environment.trace(this, "error (" + error.Line + ", " + error.Column + ") " + error.Filename + ": " + error.Message); } results.Failed = hasErrors; Environment.trace(this, "compilation done in " + ((System.nanoTime() - t0) / 1e6) + "ms"); return(results); }
private static Iterable<MemberInfo> getMembers(Library typeSystem, TypeInfo type, String name, Iterable<TypeInfo> typeArguments, bool useCache, LookupContext context) { var nTypeArgs = typeArguments.count(); foreach (var mi in (useCache) ? getCachedMembers(typeSystem, type, name) : getMembers(typeSystem, type, name)) { switch (mi.MemberKind) { case Field: if (nTypeArgs == 0 && context.lookupField) { context.lookupField = false; yield return mi; } break; case Property: if (nTypeArgs == 0 && context.lookupProperty) { context.lookupProperty = false; yield return mi; } break; case Method: if (nTypeArgs > 0) { if (nTypeArgs == mi.Method.GenericArguments.count()) { yield return MemberInfo.getInfo(typeSystem.getGenericMethod(mi.Method, typeArguments)); } } else { yield return mi; } break; case Type: if (context.lookupClass) { context.lookupClass = false; if (nTypeArgs > 0) { if (nTypeArgs == mi.Type.GenericArguments.count()) { yield return mi; } } else { if (mi.MemberKind == MemberKind.Type && mi.Type.GenericArguments.count() > 0) { mi = MemberInfo.getInfo(mi.Type.RawType); } yield return mi; } } break; } } }
public static void cloneTypes(Iterable<TypeInfo> types, Library targetTypeSystem) { var t0 = System.nanoTime(); foreach (var type in types) { defineType(type, targetTypeSystem, null); } foreach (var type in types) { declareType(type, targetTypeSystem, (TypeBuilder)targetTypeSystem.getType(type.FullName), new Scope<String, TypeInfo>()); } Environment.trace(targetTypeSystem, types.count() + " types cloned in " + ((System.nanoTime() - t0) / 1e6) + "ms"); }
MethodInfo resolveMethod(Iterable<MethodInfo> methods, Iterable<ExpressionNode> arguments, TypeInfo returnType, bool extensionMethods) { var candidates = new ArrayList<CandidateMethodInfo>(); var hasLambda = false; foreach (var method in methods) { var parameterCount = method.Parameters.count(); var argumentCount = arguments.count(); if (method.IsVarargs) { if (argumentCount < parameterCount - 1) { continue; } } else if (argumentCount != parameterCount) { continue; } var fixedArgumentCount = (method.IsVarargs) ? parameterCount - 1 : parameterCount; var isCompatible = true; var parameterTypes = new TypeInfo[argumentCount]; var expandedForm = method.IsVarargs; if (!method.IsClosed) { var typeVariableInfos = new HashMap<TypeInfo, TypeVariableInfo>(); foreach (var t in method.GenericArguments) { typeVariableInfos[t] = new TypeVariableInfo(t); } // Inference phase 1 var nit = arguments.iterator(); var pit = method.Parameters.iterator(); bool closedParams = true; for (int i = 0; i < fixedArgumentCount; i++) { var paramType = pit.next().Type; var argNode = nit.next(); if (paramType.IsClosed) { if (!isArgumentCompatible(argNode, paramType)) { goto continueLookup; } } else { closedParams = false; if (argNode.ExpressionKind == ExpressionKind.Lambda) { hasLambda = true; makeExplicitParameterTypeInference(argNode, paramType, typeVariableInfos); } else { var argInfo = argNode.getUserData(typeof(ExpressionInfo)); if (argInfo == null) { continue; } if (BytecodeHelper.isDelegateType(paramType) || BytecodeHelper.isExpressionTreeType(paramType)) { makeExplicitParameterTypeInference(argNode, paramType, typeVariableInfos); } else { ValidationHelper.getType(context, argNode); makeOutputTypeInference(argNode, paramType, typeVariableInfos); } } } } if (method.IsVarargs) { var paramType = pit.next().Type.ElementType; var isClosedParam = paramType.IsClosed; var first = true; while (nit.hasNext()) { var argNode = nit.next(); if (isClosedParam) { switch (isVarargCompatible(argNode, paramType, first)) { case False: goto continueLookup; case True: expandedForm = false; if (nit.hasNext()) { goto continueLookup; } break; } } else { closedParams = false; if (argNode.ExpressionKind == ExpressionKind.Lambda) { hasLambda = true; makeExplicitParameterTypeInference(argNode, paramType, typeVariableInfos); } else { var argInfo = argNode.getUserData(typeof(ExpressionInfo)); if (argInfo == null) { continue; } if (BytecodeHelper.isDelegateType(paramType) || BytecodeHelper.isExpressionTreeType(paramType)) { makeExplicitParameterTypeInference(argNode, paramType, typeVariableInfos); } else if (paramType != ValidationHelper.getType(context, argNode) && !ValidationHelper.isAssignable(context, paramType, argNode) && first && ValidationHelper.isAssignable(context, paramType.getArrayType(), argNode)) { expandedForm = false; makeOutputTypeInference(argNode, paramType.getArrayType(), typeVariableInfos); } else { makeOutputTypeInference(argNode, paramType, typeVariableInfos); } } } first = false; } } if (closedParams && returnType != null && returnType != context.TypeSystem.VoidType) { makeLowerBoundInference(returnType, method.ReturnType, typeVariableInfos); } // Inference phase 2 for (;;) { var varFixed = false; var hasUnfixed = false; foreach (var e in typeVariableInfos.entrySet()) { if (e.Value.fixedType != null) { continue; } if (!containsUnfixedVariables(e.getValue().dependencies, typeVariableInfos)) { if (fixTypeVariable(e.getValue())) { varFixed = true; continue; } } hasUnfixed = true; } if (!varFixed) { varFixed = false; foreach (var e in typeVariableInfos.entrySet()) { if (e.Value.fixedType != null) { continue; } if (hasUnfixedTypeVariablesDependingOn(e.Key, typeVariableInfos, new HashSet<TypeInfo>())) { if (!e.Value.bounds.isEmpty()) { if (fixTypeVariable(e.Value)) { varFixed = true; continue; } } } hasUnfixed = true; } } if (!varFixed && hasUnfixed) { goto continueLookup; } if (!hasUnfixed) { break; } var mit = method.Parameters.iterator(); TypeInfo paramType = null; foreach (var e in arguments) { if (mit.hasNext()) { paramType = mit.next().Type; } if (e.ExpressionKind != ExpressionKind.Lambda) { if (!BytecodeHelper.isDelegateType(paramType) && !BytecodeHelper.isExpressionTreeType(paramType)) { continue; } } var m = getInvokeMethod(paramType); if (hasUnfixedTypeVariables(m.ReturnType, typeVariableInfos)) { hasUnfixed = false; foreach (var p in m.Parameters) { if (hasUnfixedTypeVariables(p.Type, typeVariableInfos)) { hasUnfixed = true; break; } } if (!hasUnfixed) { makeOutputTypeInference(e, paramType, typeVariableInfos); } } } } var typeArguments = new ArrayList<TypeInfo>(); foreach (var t in method.GenericArguments) { typeArguments.add(typeVariableInfos[t].fixedType); } method = context.TypeSystem.getGenericMethod(method, typeArguments); } var it1 = arguments.iterator(); var it2 = method.Parameters.iterator(); int i; for (i = 0; i < fixedArgumentCount; i++) { var argNode = it1.next(); var paramType = it2.next().Type; parameterTypes[i] = paramType; if (!isArgumentCompatible(argNode, paramType)) { isCompatible = false; break; } else if (argNode.ExpressionKind == ExpressionKind.Lambda) { hasLambda = true; } } if (isCompatible && method.IsVarargs) { var paramType = it2.next().Type.ElementType; var first = true; while (isCompatible && it1.hasNext()) { var argNode = it1.next(); parameterTypes[i++] = paramType; switch (isVarargCompatible(argNode, paramType, first)) { case False: isCompatible = false; break; case True: expandedForm = false; if (it1.hasNext()) { isCompatible = false; break; } else if (argNode.ExpressionKind == ExpressionKind.Lambda) { hasLambda = true; } break; } first = false; } } if (isCompatible) { candidates.add(new CandidateMethodInfo(method, parameterTypes, arguments, expandedForm)); } continueLookup: ; } if (candidates.size() == 0) { return null; } CandidateMethodInfo result; if (candidates.size() > 1) { result = resolveOverloading(candidates, extensionMethods); if (result == null) { return null; } } else { result = candidates[0]; } if (hasLambda) { int parameterCount = result.method.Parameters.count(); int argumentCount = arguments.count(); int fixedArgumentCount = (result.method.IsVarargs) ? parameterCount - 1 : parameterCount; var parameterTypes = new TypeInfo[argumentCount]; var pit = result.method.getParameters().iterator(); int i; for (i = 0; i < fixedArgumentCount; i++) { parameterTypes[i] = pit.next().Type; } if (result.method.IsVarargs) { if (result.expandedForm) { var paramType = pit.next().Type.ElementType; while (i < argumentCount) { parameterTypes[i++] = paramType; } } else { parameterTypes[i] = pit.next().Type; } } i = 0; foreach (var argNode in arguments) { expressionValidator.handleExpression(argNode, parameterTypes[i], true); i++; } } return result.method; }