public static bool TryGetImplicitProperty(TemplateType template, ResolverContextStack ctxt, out AbstractType[] matchingChild) { // Check if there are only children that are named as the parent template. // That's the requirement for the special treatment. matchingChild = null; if (!ContainsEquallyNamedChildrenOnly(template.Definition)) { return(false); } // Prepare a new context bool pop = !ctxt.NodeIsInCurrentScopeHierarchy(template.Definition); if (pop) { ctxt.PushNewScope(template.Definition); } // Introduce the deduced params to the current resolution context ctxt.CurrentContext.IntroduceTemplateParameterTypes(template); // Get actual overloads, var overloads = template.Definition[template.Name]; // resolve them var resolvedOverloads = TypeDeclarationResolver.HandleNodeMatches(overloads, ctxt, null, template.DeclarationOrExpressionBase); // and deduce their parameters whereas this time, the parent's parameter are given already, in the case it's e.g. // needed as return type or in a declaration condition: // Furthermore, pass all the arguments that have been passed to the super template, to the child, // so these arguments may be used again for some inner parameters. var args = new List <ISemantic>(template.DeducedTypes.Count); foreach (var kv in template.DeducedTypes) { args.Add((ISemantic)kv.Value.ParameterValue ?? kv.Value.Base); } matchingChild = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(resolvedOverloads, args, true, ctxt); // Undo context-related changes if (pop) { ctxt.Pop(); } else { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(template); } return(matchingChild != null && matchingChild.Length == 1 && matchingChild[0] != null); }
/// <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); }