/// <summary> /// string[] s; /// /// foreach(i;s) /// { /// // i is of type 'string' /// writeln(i); /// } /// </summary> public AbstractType GetForeachIteratorType(DVariable i) { var r = new List <AbstractType>(); var curStmt = ctxt.ScopedStatement; bool init = true; // Walk up statement hierarchy -- note that foreach loops can be nested while (curStmt != null) { if (init) { init = false; } else { curStmt = curStmt.Parent; } if (curStmt is ForeachStatement) { var fe = (ForeachStatement)curStmt; if (fe.ForeachTypeList == null) { continue; } // If the searched variable is declared in the header int iteratorIndex = -1; for (int j = 0; j < fe.ForeachTypeList.Length; j++) { if (fe.ForeachTypeList[j] == i) { iteratorIndex = j; break; } } if (iteratorIndex == -1) { continue; } bool keyIsSearched = iteratorIndex == 0 && fe.ForeachTypeList.Length > 1; // foreach(var k, var v; 0 .. 9) if (keyIsSearched && fe.IsRangeStatement) { // -- it's static type int, of course(?) return(new PrimitiveType(DTokens.Int)); } var aggregateType = ExpressionTypeEvaluation.EvaluateType(fe.Aggregate, ctxt); aggregateType = DResolver.StripMemberSymbols(aggregateType); if (aggregateType == null) { return(null); } // The most common way to do a foreach if (aggregateType is AssocArrayType) { var ar = (AssocArrayType)aggregateType; return(keyIsSearched ? ar.KeyType : ar.ValueType); } else if (aggregateType is UserDefinedType) { var tr = (UserDefinedType)aggregateType; if (keyIsSearched || !(tr.Definition is IBlockNode)) { continue; } bool foundIterPropertyMatch = false; #region Foreach over Structs and Classes with Ranges // Enlist all 'back'/'front' members var t_l = new List <AbstractType>(); foreach (var n in (IBlockNode)tr.Definition) { if (fe.IsReverse ? n.Name == "back" : n.Name == "front") { t_l.Add(HandleNodeMatch(n, ctxt)); } } // Remove aliases var iterPropertyTypes = DResolver.StripAliasSymbols(t_l); foreach (var iterPropType in iterPropertyTypes) { if (iterPropType is MemberSymbol) { foundIterPropertyMatch = true; var itp = (MemberSymbol)iterPropType; // Only take non-parameterized methods if (itp.Definition is DMethod && ((DMethod)itp.Definition).Parameters.Count != 0) { continue; } // Handle its base type [return type] as iterator type if (itp.Base != null) { r.Add(itp.Base); } foundIterPropertyMatch = true; } } if (foundIterPropertyMatch) { continue; } #endregion #region Foreach over Structs and Classes with opApply t_l.Clear(); r.Clear(); foreach (var n in (IBlockNode)tr.Definition) { if (n is DMethod && (fe.IsReverse ? n.Name == "opApplyReverse" : n.Name == "opApply")) { t_l.Add(HandleNodeMatch(n, ctxt)); } } iterPropertyTypes = DResolver.StripAliasSymbols(t_l); foreach (var iterPropertyType in iterPropertyTypes) { if (iterPropertyType is MemberSymbol) { var mr = (MemberSymbol)iterPropertyType; var dm = mr.Definition as DMethod; if (dm == null || dm.Parameters.Count != 1) { continue; } var dg = dm.Parameters[0].Type as DelegateDeclaration; if (dg == null || dg.Parameters.Count != fe.ForeachTypeList.Length) { continue; } var paramType = Resolve(dg.Parameters[iteratorIndex].Type, ctxt); if (paramType != null && paramType.Length > 0) { r.Add(paramType[0]); } } } #endregion } if (r.Count > 1) { ctxt.LogError(new ResolutionError(curStmt, "Ambigous iterator type")); } return(r.Count != 0 ? r[0] : null); } } return(null); }
private static List <AbstractType> DeduceOverloads( IEnumerable <AbstractType> rawOverloadList, IEnumerable <ISemantic> givenTemplateArguments, bool isMethodCall, ResolverContextStack ctxt) { bool hasTemplateArgsPassed = givenTemplateArguments != null; if (hasTemplateArgsPassed) { var enumm = givenTemplateArguments.GetEnumerator(); hasTemplateArgsPassed = enumm.MoveNext(); enumm.Dispose(); } var filteredOverloads = new List <AbstractType>(); if (rawOverloadList == null) { return(filteredOverloads); } foreach (var o in DResolver.StripAliasSymbols(rawOverloadList)) { if (!(o is DSymbol)) { if (!hasTemplateArgsPassed) { filteredOverloads.Add(o); } continue; } var overload = (DSymbol)o; var tplNode = overload.Definition; // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params if (tplNode == null) { filteredOverloads.Add(overload); continue; } // If the type or method has got no template parameters and if there were no args passed, keep it - it's legit. if (tplNode.TemplateParameters == null) { if (!hasTemplateArgsPassed || isMethodCall) { filteredOverloads.Add(overload); } continue; } var deducedTypes = new DeducedTypeDictionary { ParameterOwner = tplNode }; foreach (var param in tplNode.TemplateParameters) { deducedTypes[param.Name] = null; // Init all params to null to let deduction functions know what params there are } if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes)) { overload.DeducedTypes = deducedTypes.ToReadonly(); // Assign calculated types to final result filteredOverloads.Add(overload); } else { overload.DeducedTypes = null; } } return(filteredOverloads); }
/// <summary> /// Takes the class passed via the tr, and resolves its base class and/or implemented interfaces. /// Also usable for enums. /// /// Never returns null. Instead, the original 'tr' object will be returned if no base class was resolved. /// Will clone 'tr', whereas the new object will contain the base class. /// </summary> public static TemplateIntermediateType ResolveClassOrInterface(DClassLike dc, ResolutionContext ctxt, ISyntaxRegion instanceDeclaration, bool ResolveFirstBaseIdOnly = false, IEnumerable <TemplateParameterSymbol> extraDeducedTemplateParams = null) { if (parsedClassInstanceDecls == null) { parsedClassInstanceDecls = new List <ISyntaxRegion> (); } switch (dc.ClassType) { case DTokens.Class: case DTokens.Interface: break; default: if (dc.BaseClasses.Count != 0) { ctxt.LogError(dc, "Only classes and interfaces may inherit from other classes/interfaces"); } return(null); } bool isClass = dc.ClassType == DTokens.Class; if (bcStack > 6 || (instanceDeclaration != null && parsedClassInstanceDecls.Contains(instanceDeclaration))) { return(isClass ? new ClassType(dc, instanceDeclaration, null) as TemplateIntermediateType : new InterfaceType(dc, instanceDeclaration)); } if (instanceDeclaration != null) { parsedClassInstanceDecls.Add(instanceDeclaration); } bcStack++; var deducedTypes = new DeducedTypeDictionary(dc); var tix = instanceDeclaration as TemplateInstanceExpression; if (tix != null && (ctxt.Options & ResolutionOptions.NoTemplateParameterDeduction) == 0) { bool hasUndeterminedArgs; var givenTemplateArguments = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt, out hasUndeterminedArgs); if (!TemplateInstanceHandler.DeduceParams(givenTemplateArguments, false, ctxt, null, dc, deducedTypes)) { parsedClassInstanceDecls.Remove(instanceDeclaration); bcStack--; return(null); } } if (extraDeducedTemplateParams != null) { foreach (var tps in extraDeducedTemplateParams) { deducedTypes[tps.Parameter] = tps; } } if (dc.BaseClasses == null || dc.BaseClasses.Count < 1) { parsedClassInstanceDecls.Remove(instanceDeclaration); bcStack--; // The Object class has no further base class; // Normal class instances have the object as base class; // Interfaces must not have any default base class/interface return(isClass ? new ClassType(dc, instanceDeclaration, dc.NameHash != ObjectNameHash ? ctxt.ParseCache.ObjectClassResult : null, null, deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null) : new InterfaceType(dc, instanceDeclaration, null, deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null) as TemplateIntermediateType); } #region Base class & interface resolution AbstractType[] res; var pop = ctxt.ScopedBlock != dc.Parent; if (pop) { ctxt.PushNewScope(dc.Parent as IBlockNode); } foreach (var kv in deducedTypes) { ctxt.CurrentContext.DeducedTemplateParameters[kv.Key] = kv.Value; } TemplateIntermediateType baseClass = null; var interfaces = new List <InterfaceType>(); try { for (int i = 0; i < (ResolveFirstBaseIdOnly ? 1 : dc.BaseClasses.Count); i++) { var type = dc.BaseClasses[i]; // If there's an explicit 'Object' inheritance, also return the pre-resolved object class if (type is IdentifierDeclaration && (type as IdentifierDeclaration).IdHash == ObjectNameHash) { if (baseClass != null) { ctxt.LogError(new ResolutionError(dc, "Class must not have two base classes")); continue; } else if (i != 0) { ctxt.LogError(new ResolutionError(dc, "The base class name must preceed base interfaces")); continue; } baseClass = ctxt.ParseCache.ObjectClassResult; continue; } if (type == null || (type is IdentifierDeclaration && (type as IdentifierDeclaration).IdHash == dc.NameHash) || dc.NodeRoot == dc) { ctxt.LogError(new ResolutionError(dc, "A class cannot inherit from itself")); continue; } res = DResolver.StripAliasSymbols(TypeDeclarationResolver.Resolve(type, ctxt)); ctxt.CheckForSingleResult(res, type); if (res != null && res.Length != 0) { var r = res[0]; if (r is ClassType || r is TemplateType) { if (!isClass) { ctxt.LogError(new ResolutionError(type, "An interface cannot inherit from non-interfaces")); } else if (i == 0) { baseClass = r as TemplateIntermediateType; } else { ctxt.LogError(new ResolutionError(dc, "The base " + (r is ClassType ? "class" : "template") + " name must preceed base interfaces")); } } else if (r is InterfaceType) { interfaces.Add(r as InterfaceType); if (isClass && dc.NameHash != ObjectNameHash && baseClass == null) { baseClass = ctxt.ParseCache.ObjectClassResult; } } else { ctxt.LogError(new ResolutionError(type, "Resolved class is neither a class nor an interface")); continue; } } } } finally { bcStack--; parsedClassInstanceDecls.Remove(instanceDeclaration); } if (pop) { ctxt.Pop(); } else { foreach (var kv in deducedTypes) // May be backup old tps? { ctxt.CurrentContext.DeducedTemplateParameters.Remove(kv.Key); } } #endregion if (isClass) { return(new ClassType(dc, instanceDeclaration, baseClass, interfaces.Count == 0 ? null : interfaces.ToArray(), deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null)); } return(new InterfaceType(dc, instanceDeclaration, interfaces.Count == 0 ? null : interfaces.ToArray(), deducedTypes.Count != 0 ? deducedTypes.ToReadonly() : null)); }
/// <summary> /// Used for searching further identifier list parts. /// /// a.b -- nextIdentifier would be 'b' whereas <param name="resultBases">resultBases</param> contained the resolution result for 'a' /// </summary> public static AbstractType[] ResolveFurtherTypeIdentifier(string nextIdentifier, IEnumerable <AbstractType> resultBases, ResolverContextStack ctxt, object typeIdObject = null) { if ((resultBases = DResolver.StripAliasSymbols(resultBases)) == null) { return(null); } var r = new List <AbstractType>(); var nextResults = new List <AbstractType>(); foreach (var b in resultBases) { IEnumerable <AbstractType> scanResults = new[] { b }; do { foreach (var scanResult in scanResults) { // First filter out all alias and member results..so that there will be only (Static-)Type or Module results left.. if (scanResult is MemberSymbol) { var mr = (MemberSymbol)scanResult; if (mr.Base != null) { nextResults.Add(mr.Base); } } else if (scanResult is UserDefinedType) { var udt = (UserDefinedType)scanResult; var bn = udt.Definition as IBlockNode; var nodeMatches = NameScan.ScanNodeForIdentifier(bn, nextIdentifier, ctxt); ctxt.PushNewScope(bn); ctxt.CurrentContext.IntroduceTemplateParameterTypes(udt); var results = HandleNodeMatches(nodeMatches, ctxt, b, typeIdObject); if (results != null) { foreach (var res in results) { r.Add(AbstractType.Get(res)); } } ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(udt); ctxt.Pop(); } else if (scanResult is PackageSymbol) { var pack = ((PackageSymbol)scanResult).Package; IAbstractSyntaxTree accessedModule = null; if (pack.Modules.TryGetValue(nextIdentifier, out accessedModule)) { r.Add(new ModuleSymbol(accessedModule as DModule, typeIdObject as ISyntaxRegion, (PackageSymbol)scanResult)); } else if (pack.Packages.TryGetValue(nextIdentifier, out pack)) { r.Add(new PackageSymbol(pack, typeIdObject as ISyntaxRegion)); } } else if (scanResult is ModuleSymbol) { var modRes = (ModuleSymbol)scanResult; var matches = NameScan.ScanNodeForIdentifier(modRes.Definition, nextIdentifier, ctxt); var results = HandleNodeMatches(matches, ctxt, b, typeIdObject); if (results != null) { foreach (var res in results) { r.Add(AbstractType.Get(res)); } } } } scanResults = DResolver.FilterOutByResultPriority(ctxt, nextResults); nextResults = new List <AbstractType>(); }while (scanResults != null); } return(r.Count == 0 ? null : r.ToArray()); }