public AbstractType Visit(DClassLike dc) { var invisibleTypeParams = GetInvisibleTypeParameters(dc); switch (dc.ClassType) { case DTokens.Struct: return(new StructType(dc, typeBase, invisibleTypeParams)); case DTokens.Union: return(new UnionType(dc, typeBase, invisibleTypeParams)); case DTokens.Interface: case DTokens.Class: return(DResolver.ResolveClassOrInterface(dc, ctxt, typeBase, false, invisibleTypeParams)); case DTokens.Template: if (dc.ContainsAttribute(DTokens.Mixin)) { return(new MixinTemplateType(dc, typeBase, invisibleTypeParams)); } return(new TemplateType(dc, typeBase, invisibleTypeParams)); default: ctxt.LogError(new ResolutionError(dc, "Unknown type (" + DTokens.GetTokenString(dc.ClassType) + ")")); return(null); } }
protected override bool HandleItem(INode n) { if ((nameFilterHash != 0 && n.NameHash != nameFilterHash) || !(n.Parent is DModule)) { return(false); } DVariable dv; var dc = n as DClassLike; if (dc != null && dc.ClassType == DTokens.Template) { if (sr is TemplateInstanceExpression || nameFilterHash == 0) { var templ = TypeDeclarationResolver.HandleNodeMatch(dc, ctxt, null, sr); templ.Tag = new UfcsTag { firstArgument = firstArgument }; matches.Add(templ); } } else if (n is DMethod) { HandleMethod(n as DMethod); } else if ((dv = n as DVariable) != null && dv.IsAlias) { var t = TypeDeclarationResolver.HandleNodeMatch(n, ctxt, null, sr); var t_ = DResolver.StripAliasSymbol(t) as DSymbol; if (t_ != null) { if (t_ is MemberSymbol && t_.Definition is DMethod) { HandleMethod(t_.Definition as DMethod, t_ as MemberSymbol); } else if (t_.Definition is DClassLike) { t_.Tag = new UfcsTag { firstArgument = firstArgument }; matches.Add(t_); } // Perhaps other types may occur here as well - but which remain then to be added? } } return(false); }
public static AbstractType Resolve(ArrayDecl ad, ResolutionContext ctxt) { var valueTypes = Resolve(ad.ValueType, ctxt); ctxt.CheckForSingleResult(valueTypes, ad); AbstractType valueType = null; AbstractType keyType = null; int fixedArrayLength = -1; if (valueTypes != null && valueTypes.Length != 0) { valueType = valueTypes[0]; } ISymbolValue val; keyType = ResolveKey(ad, out fixedArrayLength, out val, ctxt); if (keyType == null || (keyType is PrimitiveType && ((PrimitiveType)keyType).TypeToken == DTokens.Int)) { if (fixedArrayLength >= 0) { // D Magic: One might access tuple items directly in the pseudo array declaration - so stuff like Tup[0] i; becomes e.g. int i; var dtup = DResolver.StripMemberSymbols(valueType) as DTuple; if (dtup == null) { return(new ArrayType(valueType, fixedArrayLength, ad)); } if (dtup.Items != null && fixedArrayLength < dtup.Items.Length) { return(AbstractType.Get(dtup.Items [fixedArrayLength])); } else { ctxt.LogError(ad, "TypeTuple only consists of " + (dtup.Items != null ? dtup.Items.Length : 0) + " items. Can't access item at index " + fixedArrayLength); return(null); } } return(new ArrayType(valueType, ad)); } return(new AssocArrayType(valueType, keyType, ad)); }
public AbstractType Visit(DVariable variable) { AbstractType bt; if (CanResolveBase(variable)) { var bts = TypeDeclarationResolver.Resolve(variable.Type, ctxt); if (bts != null && bts.Length != 0) { bt = bts[0]; } // For auto variables, use the initializer to get its type else if (variable.Initializer != null) { bt = DResolver.StripMemberSymbols(ExpressionTypeEvaluation.EvaluateType(variable.Initializer, ctxt)); } else { bt = null; } // Check if inside an foreach statement header if (bt == null && ctxt.ScopedStatement != null) { bt = GetForeachIteratorType(variable); } if (bt == null) { ctxt.CheckForSingleResult(bts, variable.Type as ISyntaxRegion ?? variable.Initializer); } } else { bt = null; } // Note: Also works for aliases! In this case, we simply try to resolve the aliased type, otherwise the variable's base type return(variable.IsAlias ? new AliasedType(variable, bt, typeBase) : new MemberSymbol(variable, bt, typeBase)); }
public static AbstractType Resolve(TypeOfDeclaration typeOf, ResolutionContext ctxt) { // typeof(return) if (typeOf.Expression is TokenExpression && (typeOf.Expression as TokenExpression).Token == DTokens.Return) { var m = HandleNodeMatch(ctxt.ScopedBlock, ctxt, null, typeOf); if (m != null) { return(m); } } // typeOf(myInt) => int else if (typeOf.Expression != null) { var wantedTypes = ExpressionTypeEvaluation.EvaluateType(typeOf.Expression, ctxt); return(DResolver.StripMemberSymbols(wantedTypes)); } return(null); }
/// <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); }
public static AbstractType ResolveKey(ArrayDecl ad, out int fixedArrayLength, out ISymbolValue keyVal, ResolutionContext ctxt) { keyVal = null; fixedArrayLength = -1; AbstractType keyType = null; if (ad.KeyExpression != null) { //TODO: Template instance expressions? var id_x = ad.KeyExpression as IdentifierExpression; if (id_x != null && id_x.IsIdentifier) { var id = new IdentifierDeclaration((string)id_x.Value) { Location = id_x.Location, EndLocation = id_x.EndLocation }; keyType = TypeDeclarationResolver.ResolveSingle(id, ctxt); if (keyType != null) { var tt = DResolver.StripAliasSymbol(keyType) as MemberSymbol; if (tt == null || !(tt.Definition is DVariable) || ((DVariable)tt.Definition).Initializer == null) { return(keyType); } } } try { keyVal = Evaluation.EvaluateValue(ad.KeyExpression, ctxt); if (keyVal != null) { // Take the value's type as array key type keyType = keyVal.RepresentedType; // It should be mostly a number only that points out how large the final array should be var pv = Evaluation.GetVariableContents(keyVal, new StandardValueProvider(ctxt)) as PrimitiveValue; if (pv != null) { fixedArrayLength = System.Convert.ToInt32(pv.Value); if (fixedArrayLength < 0) { ctxt.LogError(ad, "Invalid array size: Length value must be greater than 0"); } } //TODO Is there any other type of value allowed? } } catch { } } else { var t = Resolve(ad.KeyType, ctxt); ctxt.CheckForSingleResult(t, ad.KeyType); if (t != null && t.Length != 0) { return(t[0]); } } return(keyType); }
/// <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(int nextIdentifierHash, IEnumerable <AbstractType> resultBases, ResolutionContext ctxt, ISyntaxRegion typeIdObject = null) { MemberSymbol statProp; if ((resultBases = DResolver.StripMemberSymbols(resultBases)) == null) { return(null); } var r = new List <AbstractType>(); foreach (var b in resultBases) { if (b is UserDefinedType) { var udt = b as UserDefinedType; var bn = udt.Definition as IBlockNode; bool pop = b is MixinTemplateType; if (pop) { ctxt.PushNewScope(bn); } ctxt.CurrentContext.IntroduceTemplateParameterTypes(udt); r.AddRange(SingleNodeNameScan.SearchChildrenAndResolve(ctxt, udt, nextIdentifierHash, typeIdObject)); List <TemplateParameterSymbol> dedTypes = null; foreach (var t in r) { var ds = t as DSymbol; if (ds != null && ds.DeducedTypes == null) { if (dedTypes == null) { dedTypes = ctxt.DeducedTypesInHierarchy; } ds.DeducedTypes = new System.Collections.ObjectModel.ReadOnlyCollection <TemplateParameterSymbol>(dedTypes); } } statProp = StaticProperties.TryEvalPropertyType(ctxt, b, nextIdentifierHash); if (statProp != null) { r.Add(statProp); } // go the opDispatch way if possible - http://dlang.org/operatoroverloading.html#Dispatch if (r.Count == 0 && nextIdentifierHash != OpDispatchResolution.opDispatchId) { r.AddRange(OpDispatchResolution.TryResolveFurtherIdViaOpDispatch(ctxt, nextIdentifierHash, udt)); } if (r.Count == 0) { r.AddRange(UFCSResolver.TryResolveUFCS(b, nextIdentifierHash, !pop && typeIdObject != null ? typeIdObject.Location : ctxt.ScopedBlock.BlockStartLocation, ctxt, typeIdObject)); } if (pop) { ctxt.Pop(); } else { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(udt); } } else if (b is PackageSymbol) { var pack = (b as PackageSymbol).Package; var accessedModule = pack.GetModule(nextIdentifierHash); if (accessedModule != null) { r.Add(new ModuleSymbol(accessedModule as DModule, typeIdObject as ISyntaxRegion, b as PackageSymbol)); } else if ((pack = pack.GetPackage(nextIdentifierHash)) != null) { r.Add(new PackageSymbol(pack, typeIdObject as ISyntaxRegion)); } } else if (b is ModuleSymbol) { r.AddRange(SingleNodeNameScan.SearchChildrenAndResolve(ctxt, b as ModuleSymbol, nextIdentifierHash, typeIdObject)); } else { statProp = StaticProperties.TryEvalPropertyType(ctxt, b, nextIdentifierHash); if (statProp != null) { r.Add(statProp); } if (r.Count == 0) // Only if there hasn't been a result yet? { r.AddRange(UFCSResolver.TryResolveUFCS(b, nextIdentifierHash, typeIdObject != null ? typeIdObject.Location : ctxt.ScopedBlock.BlockStartLocation, ctxt, typeIdObject)); } } } return(r.Count == 0 ? null : r.ToArray()); }
public static AbstractType GetMethodReturnType(DMethod method, ResolutionContext ctxt) { if ((ctxt.Options & ResolutionOptions.DontResolveBaseTypes) == ResolutionOptions.DontResolveBaseTypes) { return(null); } /* * If a method's type equals null, assume that it's an 'auto' function.. * 1) Search for a return statement * 2) Resolve the returned expression * 3) Use that one as the method's type */ bool pushMethodScope = ctxt.ScopedBlock != method; if (method.Type != null) { if (pushMethodScope) { ctxt.PushNewScope(method); } //FIXME: Is it legal to explicitly return a nested type? var returnType = TypeDeclarationResolver.Resolve(method.Type, ctxt); if (pushMethodScope) { ctxt.Pop(); } ctxt.CheckForSingleResult(returnType, method.Type); if (returnType != null && returnType.Length > 0) { return(returnType[0]); } } else if (method.Body != null) { ReturnStatement returnStmt = null; var list = new List <IStatement> { method.Body }; var list2 = new List <IStatement>(); bool foundMatch = false; while (!foundMatch && list.Count > 0) { foreach (var stmt in list) { if (stmt is ReturnStatement) { returnStmt = stmt as ReturnStatement; var te = returnStmt.ReturnExpression as TokenExpression; if (te == null || te.Token != DTokens.Null) { foundMatch = true; break; } } var statementContainingStatement = stmt as StatementContainingStatement; if (statementContainingStatement != null) { list2.AddRange(statementContainingStatement.SubStatements); } } list = list2; list2 = new List <IStatement>(); } if (returnStmt != null && returnStmt.ReturnExpression != null) { if (pushMethodScope) { var dedTypes = ctxt.CurrentContext.DeducedTemplateParameters; ctxt.PushNewScope(method, returnStmt); if (dedTypes.Count != 0) { foreach (var kv in dedTypes) { ctxt.CurrentContext.DeducedTemplateParameters[kv.Key] = kv.Value; } } } var t = DResolver.StripMemberSymbols(ExpressionTypeEvaluation.EvaluateType(returnStmt.ReturnExpression, ctxt)); if (pushMethodScope) { ctxt.Pop(); } return(t); } return(new PrimitiveType(DTokens.Void)); } return(null); }
/// <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)); }
private static bool DeduceParam(ResolverContextStack ctxt, DSymbol overload, DeducedTypeDictionary deducedTypes, IEnumerator <ISemantic> argEnum, ITemplateParameter expectedParam) { if (expectedParam is TemplateThisParameter && overload.Base != null) { var ttp = (TemplateThisParameter)expectedParam; // Get the type of the type of 'this' - so of the result that is the overload's base var t = DResolver.StripMemberSymbols(overload.Base); if (t == null || t.DeclarationOrExpressionBase == null) { return(false); } //TODO: Still not sure if it's ok to pass a type result to it // - looking at things like typeof(T) that shall return e.g. const(A) instead of A only. if (!CheckAndDeduceTypeAgainstTplParameter(ttp, t, deducedTypes, ctxt)) { return(false); } return(true); } // Used when no argument but default arg given bool useDefaultType = false; if (argEnum.MoveNext() || (useDefaultType = HasDefaultType(expectedParam))) { // On tuples, take all following arguments and pass them to the check function if (expectedParam is TemplateTupleParameter) { var tupleItems = new List <ISemantic>(); // A tuple must at least contain one item! tupleItems.Add(argEnum.Current); while (argEnum.MoveNext()) { tupleItems.Add(argEnum.Current); } if (!CheckAndDeduceTypeTuple((TemplateTupleParameter)expectedParam, tupleItems, deducedTypes, ctxt)) { return(false); } } else if (argEnum.Current != null) { if (!CheckAndDeduceTypeAgainstTplParameter(expectedParam, argEnum.Current, deducedTypes, ctxt)) { return(false); } } else if (useDefaultType && CheckAndDeduceTypeAgainstTplParameter(expectedParam, null, deducedTypes, ctxt)) { // It's legit - just do nothing } else { return(false); } } // There might be too few args - but that doesn't mean that it's not correct - it's only required that all parameters got satisfied with a type else if (!AllParamatersSatisfied(deducedTypes)) { return(false); } return(true); }
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> /// The variable's or method's base type will be resolved (if auto type, the intializer's type will be taken). /// A class' base class will be searched. /// etc.. /// </summary> public static AbstractType HandleNodeMatch( INode m, ResolverContextStack ctxt, AbstractType resultBase = null, object typeBase = null) { stackNum_HandleNodeMatch++; /* * Pushing a new scope is only required if current scope cannot be found in the handled node's hierarchy. */ bool popAfterwards = !ctxt.NodeIsInCurrentScopeHierarchy(m); if (popAfterwards) { ctxt.PushNewScope(m is IBlockNode ? (IBlockNode)m : m.Parent as IBlockNode); } //HACK: Really dirty stack overflow prevention via manually counting call depth var canResolveBaseGenerally = stackNum_HandleNodeMatch < 6; var DoResolveBaseType = canResolveBaseGenerally && !ctxt.Options.HasFlag(ResolutionOptions.DontResolveBaseClasses) && (m.Type == null || m.Type.ToString(false) != m.Name); AbstractType ret = null; // To support resolving type parameters to concrete types if the context allows this, introduce all deduced parameters to the current context if (canResolveBaseGenerally && resultBase is DSymbol) { ctxt.CurrentContext.IntroduceTemplateParameterTypes((DSymbol)resultBase); } // Only import symbol aliases are allowed to search in the parse cache if (m is ImportSymbolAlias) { var isa = (ImportSymbolAlias)m; if (isa.IsModuleAlias ? isa.Type != null : isa.Type.InnerDeclaration != null) { var mods = new List <DModule>(); var td = isa.IsModuleAlias ? isa.Type : isa.Type.InnerDeclaration; foreach (var mod in ctxt.ParseCache.LookupModuleName(td.ToString())) { mods.Add(mod as DModule); } if (mods.Count == 0) { ctxt.LogError(new NothingFoundError(isa.Type)); } else if (mods.Count > 1) { var m__ = new List <ISemantic>(); foreach (var mod in mods) { m__.Add(new ModuleSymbol(mod, isa.Type)); } ctxt.LogError(new AmbiguityError(isa.Type, m__)); } var bt = mods.Count != 0 ? (AbstractType) new ModuleSymbol(mods[0], td) : null; //TODO: Is this correct behaviour? if (!isa.IsModuleAlias) { var furtherId = ResolveFurtherTypeIdentifier(isa.Type.ToString(false), new[] { bt }, ctxt, isa.Type); ctxt.CheckForSingleResult(furtherId, isa.Type); if (furtherId != null && furtherId.Length != 0) { bt = furtherId[0]; } else { bt = null; } } ret = new AliasedType(isa, bt, isa.Type); } } else if (m is DVariable) { var v = (DVariable)m; AbstractType bt = null; if (DoResolveBaseType) { var bts = TypeDeclarationResolver.Resolve(v.Type, ctxt); if (bts != null && bts.Length != 0 && ctxt.CheckForSingleResult(bts, v.Type)) { bt = bts[0]; } // For auto variables, use the initializer to get its type else if (v.Initializer != null) { bt = ExpressionSemantics.Evaluation.EvaluateType(v.Initializer, ctxt); } // Check if inside an foreach statement header if (bt == null && ctxt.ScopedStatement != null) { bt = GetForeachIteratorType(v, ctxt); } } // Note: Also works for aliases! In this case, we simply try to resolve the aliased type, otherwise the variable's base type ret = v.IsAlias ? (DSymbol) new AliasedType(v, bt, typeBase as ISyntaxRegion) : new MemberSymbol(v, bt, typeBase as ISyntaxRegion); } else if (m is DMethod) { ret = new MemberSymbol((DNode)m, DoResolveBaseType ? GetMethodReturnType((DMethod)m, ctxt) : null , typeBase as ISyntaxRegion); } else if (m is DClassLike) { UserDefinedType udt = null; var dc = (DClassLike)m; var invisibleTypeParams = new Dictionary <string, TemplateParameterSymbol>(); /* * Add 'superior' template parameters to the current symbol because the parameters * might be re-used in the nested class. */ var tStk = new Stack <ResolverContext>(); do { var curCtxt = ctxt.Pop(); tStk.Push(curCtxt); foreach (var kv in curCtxt.DeducedTemplateParameters) { if (!dc.ContainsTemplateParameter(kv.Key) && !invisibleTypeParams.ContainsKey(kv.Key)) { invisibleTypeParams.Add(kv.Key, kv.Value); } } } while (ctxt.PrevContextIsInSameHierarchy); while (tStk.Count != 0) { ctxt.Push(tStk.Pop()); } switch (dc.ClassType) { case DTokens.Struct: ret = new StructType(dc, typeBase as ISyntaxRegion, invisibleTypeParams); break; case DTokens.Union: ret = new UnionType(dc, typeBase as ISyntaxRegion, invisibleTypeParams); break; case DTokens.Class: udt = new ClassType(dc, typeBase as ISyntaxRegion, null, null, invisibleTypeParams); break; case DTokens.Interface: udt = new InterfaceType(dc, typeBase as ISyntaxRegion, null, invisibleTypeParams); break; case DTokens.Template: ret = new TemplateType(dc, typeBase as ISyntaxRegion, invisibleTypeParams); break; default: ctxt.LogError(new ResolutionError(m, "Unknown type (" + DTokens.GetTokenString(dc.ClassType) + ")")); break; } if (dc.ClassType == DTokens.Class || dc.ClassType == DTokens.Interface) { if (canResolveBaseGenerally && !ctxt.Options.HasFlag(ResolutionOptions.DontResolveBaseClasses)) { ret = DResolver.ResolveBaseClasses(udt, ctxt); } else { ret = udt; } } } else if (m is IAbstractSyntaxTree) { var mod = (IAbstractSyntaxTree)m; if (typeBase != null && typeBase.ToString() != mod.ModuleName) { var pack = ctxt.ParseCache.LookupPackage(typeBase.ToString()).First(); if (pack != null) { ret = new PackageSymbol(pack, typeBase as ISyntaxRegion); } } else { ret = new ModuleSymbol(m as DModule, typeBase as ISyntaxRegion); } } else if (m is DEnum) { ret = new EnumType((DEnum)m, typeBase as ISyntaxRegion); } else if (m is TemplateParameterNode) { //ResolveResult[] templateParameterType = null; //TODO: Resolve the specialization type //var templateParameterType = TemplateInstanceHandler.ResolveTypeSpecialization(tmp, ctxt); ret = new TemplateParameterSymbol((TemplateParameterNode)m, null, typeBase as ISyntaxRegion); } if (canResolveBaseGenerally && resultBase is DSymbol) { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals((DSymbol)resultBase); } if (popAfterwards) { ctxt.Pop(); } stackNum_HandleNodeMatch--; return(ret); }
/// <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()); }
public static List <ISemantic> PreResolveTemplateArgs(TemplateInstanceExpression tix, ResolutionContext ctxt, out bool hasNonFinalArgument) { hasNonFinalArgument = false; // Resolve given argument expressions var templateArguments = new List <ISemantic>(); if (tix != null && tix.Arguments != null) { foreach (var arg in tix.Arguments) { if (arg is TypeDeclarationExpression) { var tde = (TypeDeclarationExpression)arg; var res = TypeDeclarationResolver.Resolve(tde.Declaration, ctxt); // Might be a simple symbol without any applied template arguments that is then passed to an template alias parameter if (res == null && tde.Declaration is IdentifierDeclaration) { res = TypeDeclarationResolver.Resolve(tde.Declaration as IdentifierDeclaration, ctxt, null, false); } if (ctxt.CheckForSingleResult(res, tde.Declaration) || (res != null && res.Length > 0)) { var mr = res[0] as MemberSymbol; if (mr != null && mr.Definition is DVariable) { var dv = (DVariable)mr.Definition; if (dv.IsAlias || dv.Initializer == null) { templateArguments.Add(mr); continue; } ISemantic eval = null; try { eval = new StandardValueProvider(ctxt)[dv]; } catch (System.Exception ee) // Should be a non-const-expression error here only { ctxt.LogError(dv.Initializer, ee.Message); } templateArguments.Add(eval ?? (ISemantic)mr); } else { if (!hasNonFinalArgument) { hasNonFinalArgument = IsNonFinalArgument(res[0]); } templateArguments.Add(res[0]); } } } else { ISemantic v = Evaluation.EvaluateValue(arg, ctxt, true); if (v is VariableValue) { var vv = v as VariableValue; if (vv.Variable.IsConst && vv.Variable.Initializer != null) { v = Evaluation.EvaluateValue(vv, new StandardValueProvider(ctxt)); } } if (!hasNonFinalArgument) { hasNonFinalArgument = IsNonFinalArgument(v); } v = DResolver.StripValueTypeWrappers(v); templateArguments.Add(v); } } } return(templateArguments); }