public AbstractType Visit(DEnum de) { AbstractType bt; if (de.Type == null) { bt = new PrimitiveType(DTokens.Int); } else { var pop = de.Parent is IBlockNode && ctxt.ScopedBlock != de.Parent; if (pop) { ctxt.PushNewScope(de.Parent as IBlockNode); } var bts = TypeDeclarationResolver.Resolve(de.Type, ctxt); if (pop) { ctxt.Pop(); } ctxt.CheckForSingleResult(bts, de.Type); bt = bts != null && bts.Length != 0 ? bts[0] : null; } return(new EnumType(de, bt, typeBase)); }
/// <summary> /// Resolves an identifier and returns the definition + its base type. /// Does not deduce any template parameters or nor filters out unfitting template specifications! /// </summary> public static AbstractType[] ResolveIdentifier(int idHash, ResolutionContext ctxt, object idObject, bool ModuleScope = false) { var loc = idObject is ISyntaxRegion ? ((ISyntaxRegion)idObject).Location : CodeLocation.Empty; if (ModuleScope) { ctxt.PushNewScope(ctxt.ScopedBlock.NodeRoot as DModule); } // If there are symbols that must be preferred, take them instead of scanning the ast else { TemplateParameterSymbol dedTemplateParam; if (ctxt.GetTemplateParam(idHash, out dedTemplateParam)) { return new[] { dedTemplateParam } } ; } var res = NameScan.SearchAndResolve(ctxt, loc, idHash, idObject); if (ModuleScope) { ctxt.Pop(); } return /*res.Count == 0 ? null :*/ (res.ToArray()); }
static AbstractType[] TryGetImplicitProperty(TemplateType template, ResolutionContext ctxt) { // Prepare a new context bool pop = !ctxt.ScopedBlockIsInNodeHierarchy(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 matchingChild = TypeDeclarationResolver.ResolveFurtherTypeIdentifier(template.NameHash, new[] { template }, ctxt); // Undo context-related changes if (pop) { ctxt.Pop(); } else { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(template); } return(matchingChild); }
static string GetMixinContent(MixinStatement mx, ResolutionContext ctxt, bool takeStmtCache ,out ISyntaxRegion cachedContent) { cachedContent = null; if(!CheckAndPushAnalysisStack(mx)) return null; bool pop; if(pop = (ctxt.ScopedBlock != mx.ParentNode && mx.ParentNode != null)) ctxt.PushNewScope(mx.ParentNode as IBlockNode, mx); bool hadCachedItem; if(takeStmtCache) { BlockStatement stmt; hadCachedItem = mixinStmtCache.TryGet(ctxt, mx, out stmt); cachedContent = stmt; } else { DModule mod; hadCachedItem = mixinDeclCache.TryGet(ctxt, mx, out mod); cachedContent = mod; } if(hadCachedItem) { stmtsBeingAnalysed.Remove(mx); if(pop) ctxt.Pop(); return null; } var x = mx.MixinExpression; ISemantic v = null; try // 'try' because there is always a risk of e.g. not having something implemented or having an evaluation exception... { // Evaluate the mixin expression v = Evaluation.EvaluateValue(x, ctxt); } catch{} stmtsBeingAnalysed.Remove(mx); if(pop) ctxt.Pop(); // Ensure it's a string literal var av = v as ArrayValue; if(av != null && av.IsString) return av.StringValue; if(takeStmtCache) mixinStmtCache.Add(ctxt, mx, null); else mixinDeclCache.Add(ctxt, mx, null); return null; }
public static MemberSymbol[] TryResolveUFCS( ISemantic firstArgument, PostfixExpression_Access acc, ResolutionContext ctxt) { if (ctxt == null) return null; int name=0; if (acc.AccessExpression is IdentifierExpression) name = ((IdentifierExpression)acc.AccessExpression).ValueStringHash; else if (acc.AccessExpression is TemplateInstanceExpression) name = ((TemplateInstanceExpression)acc.AccessExpression).TemplateIdHash; else return null; var methodMatches = new List<MemberSymbol>(); if(ctxt.ParseCache!=null) foreach (var pc in ctxt.ParseCache) { var tempResults=pc.UfcsCache.FindFitting(ctxt, acc.Location, firstArgument, name); if (tempResults != null) foreach (var m in tempResults) { ctxt.PushNewScope(m); if (m.TemplateParameters != null && m.TemplateParameters.Length != 0) { var ov = TemplateInstanceHandler.DeduceParamsAndFilterOverloads( new[] { new MemberSymbol(m, null, acc) }, new[] { firstArgument }, true, ctxt); if (ov == null || ov.Length == 0) continue; var ms = (DSymbol)ov[0]; ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); } var mr = TypeDeclarationResolver.HandleNodeMatch(m, ctxt, null, acc) as MemberSymbol; if (mr!=null) { mr.FirstArgument = firstArgument; mr.DeducedTypes = ctxt.CurrentContext.DeducedTemplateParameters.ToReadonly(); mr.IsUFCSResult = true; methodMatches.Add(mr); } ctxt.Pop(); } } return methodMatches.Count == 0 ? null : methodMatches.ToArray(); }
public override void VisitAbstractStmt(AbstractStatement stmt) { var back = ctxt.ScopedStatement; bool pop = false; if (back != stmt) { var parentNode = stmt.ParentNode; if (parentNode != null && ctxt.ScopedBlock != parentNode) { ctxt.PushNewScope(stmt.ParentNode as IBlockNode, stmt); pop = true; } else if (ctxt.ScopedBlock != null) { ctxt.CurrentContext.Set(stmt); } else { back = stmt; } OnScopedStatementChanged(stmt); } base.VisitAbstractStmt(stmt); if (back != stmt) { if (!pop) { ctxt.CurrentContext.Set(back); } else { ctxt.Pop(); } } }
/// <summary> /// Resolves an identifier and returns the definition + its base type. /// Does not deduce any template parameters or nor filters out unfitting template specifications! /// </summary> public static AbstractType[] ResolveIdentifier(int idHash, ResolutionContext ctxt, ISyntaxRegion idObject, bool ModuleScope = false) { var loc = idObject is ISyntaxRegion ? ((ISyntaxRegion)idObject).Location : CodeLocation.Empty; if (ModuleScope) { ctxt.PushNewScope(ctxt.ScopedBlock.NodeRoot as DModule); } // If there are symbols that must be preferred, take them instead of scanning the ast else { TemplateParameterSymbol dedTemplateParam; if (ctxt.GetTemplateParam(idHash, out dedTemplateParam)) { return new[] { dedTemplateParam } } ; } var res = NameScan.SearchAndResolve(ctxt, loc, idHash, idObject); if (ModuleScope) { ctxt.Pop(); } if (res.Count != 0) { return /*res.Count == 0 ? null :*/ (res.ToArray()); } // Support some very basic static typing if no phobos is given atm if (idHash == Evaluation.stringTypeHash) { res.Add(Evaluation.GetStringType(ctxt)); } else if (idHash == Evaluation.wstringTypeHash) { res.Add(Evaluation.GetStringType(ctxt, LiteralSubformat.Utf16)); } else if (idHash == Evaluation.dstringTypeHash) { res.Add(Evaluation.GetStringType(ctxt, LiteralSubformat.Utf32)); } return(res.ToArray()); }
static AbstractType[] TryGetImplicitProperty(TemplateType template, ResolutionContext ctxt) { // Prepare a new context bool pop = !ctxt.ScopedBlockIsInNodeHierarchy(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 matchingChild = TypeDeclarationResolver.ResolveFurtherTypeIdentifier(template.NameHash, new[] { template }, ctxt); if (matchingChild != null) // Currently requried for proper UFCS resolution - sustain template's Tag { foreach (var ch in matchingChild) { var ds = ch as DSymbol; if (ds != null) { var newDeducedTypes = new DeducedTypeDictionary(ds); foreach (var tps in template.DeducedTypes) { newDeducedTypes[tps.Parameter] = tps; } ds.DeducedTypes = newDeducedTypes.ToReadonly(); } ch.Tag = template.Tag; } } // Undo context-related changes if (pop) { ctxt.Pop(); } else { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(template); } return(matchingChild); }
/// <summary> /// http://dlang.org/operatoroverloading.html#Dispatch /// Check for the existence of an opDispatch overload. /// Important: Because static opDispatches are allowed as well, do check whether we can access non-static overloads from non-instance expressions or such /// </summary> public static IEnumerable <AbstractType> TryResolveFurtherIdViaOpDispatch(ResolutionContext ctxt, int nextIdentifierHash, UserDefinedType b) { // The usual SO prevention if (nextIdentifierHash == opDispatchId || b == null) { yield break; } var pop = ctxt.ScopedBlock != b.Definition; if (pop) { // Mainly required for not resolving opDispatch's return type, as this will be performed later on in higher levels var opt = ctxt.CurrentContext.ContextDependentOptions; ctxt.PushNewScope(b.Definition as IBlockNode); ctxt.CurrentContext.IntroduceTemplateParameterTypes(b); ctxt.CurrentContext.ContextDependentOptions = opt; } // Look for opDispatch-Members inside b's Definition var overloads = TypeDeclarationResolver.ResolveFurtherTypeIdentifier(opDispatchId, new[] { b }, ctxt); if (pop) { ctxt.Pop(); } if (overloads == null || overloads.Length < 0) { yield break; } var av = new ArrayValue(Evaluation.GetStringType(ctxt), Strings.TryGet(nextIdentifierHash)); foreach (DSymbol o in overloads) { var dn = o.Definition; if (dn.TemplateParameters != null && dn.TemplateParameters.Length > 0 && dn.TemplateParameters[0] is TemplateValueParameter) { //TODO: Test parameter types for being a string value o.DeducedTypes = new System.Collections.ObjectModel.ReadOnlyCollection <TemplateParameterSymbol> ( new[] { new TemplateParameterSymbol(dn.TemplateParameters[0], av) }); yield return(o); } } }
/// <summary> /// Resolves an identifier and returns the definition + its base type. /// Does not deduce any template parameters or nor filters out unfitting template specifications! /// </summary> public static AbstractType[] ResolveIdentifier(int idHash, ResolutionContext ctxt, object idObject, bool ModuleScope = false) { var loc = idObject is ISyntaxRegion ? ((ISyntaxRegion)idObject).Location : CodeLocation.Empty; if (ModuleScope) ctxt.PushNewScope(ctxt.ScopedBlock.NodeRoot as DModule); // If there are symbols that must be preferred, take them instead of scanning the ast else { TemplateParameterSymbol dedTemplateParam; if (ctxt.GetTemplateParam(idHash, out dedTemplateParam)) return new[] { dedTemplateParam }; } var res = NameScan.SearchAndResolve(ctxt, loc, idHash, idObject); if (ModuleScope) ctxt.Pop(); return /*res.Count == 0 ? null :*/ res.ToArray(); }
/// <summary> /// </summary> /// <param name="ast">Сканируемое синтаксическое дерево</param> /// <param name="symbol">Не может быть символом-пасынком АСТ</param> /// <param name="ctxt">Контекст, необходимый для поиска символов</param> /// <returns></returns> public static IEnumerable <ISyntaxRegion> Scan(DModule ast, INode symbol, ResolutionContext ctxt, bool includeDefinition = true) { if (ast == null || symbol == null || ctxt == null) { return(null); } ctxt.PushNewScope(ast); var f = new ReferencesFinder(symbol, ast, ctxt); ast.Accept(f); ctxt.Pop(); var nodeRoot = symbol.NodeRoot as DModule; if (includeDefinition && nodeRoot != null && nodeRoot.FileName == ast.FileName) { var dc = symbol.Parent as DClassLike; if (dc != null && dc.ClassType == DSharp.Parser.DTokens.Template && dc.NameHash == symbol.NameHash) { f.l.Insert(0, new IdentifierDeclaration(dc.NameHash) { Location = dc.NameLocation, EndLocation = new CodeLocation(dc.NameLocation.Column + dc.Name.Length, dc.NameLocation.Line) }); } f.l.Insert(0, new IdentifierDeclaration(symbol.NameHash) { Location = symbol.NameLocation, EndLocation = new CodeLocation(symbol.NameLocation.Column + symbol.Name.Length, symbol.NameLocation.Line) }); } return(f.l); }
/// <summary> /// http://dlang.org/operatoroverloading.html#Dispatch /// Check for the existence of an opDispatch overload. /// Important: Because static opDispatches are allowed as well, do check whether we can access non-static overloads from non-instance expressions or such /// </summary> public static IEnumerable<AbstractType> TryResolveFurtherIdViaOpDispatch(ResolutionContext ctxt, int nextIdentifierHash, UserDefinedType b) { // The usual SO prevention if (nextIdentifierHash == opDispatchId || b == null) yield break; var pop = ctxt.ScopedBlock != b.Definition; if (pop) { // Mainly required for not resolving opDispatch's return type, as this will be performed later on in higher levels var opt = ctxt.CurrentContext.ContextDependentOptions; ctxt.PushNewScope (b.Definition as IBlockNode); ctxt.CurrentContext.IntroduceTemplateParameterTypes (b); ctxt.CurrentContext.ContextDependentOptions = opt; } // Look for opDispatch-Members inside b's Definition var overloads = TypeDeclarationResolver.ResolveFurtherTypeIdentifier (opDispatchId, new[]{b}, ctxt); if(pop) ctxt.Pop (); if (overloads == null || overloads.Length < 0) yield break; var av = new ArrayValue (Evaluation.GetStringType(ctxt), Strings.TryGet(nextIdentifierHash)); foreach (DSymbol o in overloads) { var dn = o.Definition; if (dn.TemplateParameters != null && dn.TemplateParameters.Length > 0 && dn.TemplateParameters[0] is TemplateValueParameter) { //TODO: Test parameter types for being a string value o.DeducedTypes = new System.Collections.ObjectModel.ReadOnlyCollection<TemplateParameterSymbol> ( new[]{ new TemplateParameterSymbol(dn.TemplateParameters[0], av) } ); yield return o; } } }
bool IsMoreSpecialized(ITypeDeclaration Spec, TemplateParameter t2, Dictionary <TemplateParameter, ISemantic> t1_DummyParamList) { // Make a type out of t1's specialization var pop = ctxt.ScopedBlock != null; if (pop) { ctxt.PushNewScope(ctxt.ScopedBlock.Parent as IBlockNode); } var frame = ctxt.CurrentContext; // Make the T in e.g. T[] a virtual type so T will be replaced by it // T** will be X** then - so a theoretically valid type instead of a template param var dummyType = new ClassType(new DClassLike { Name = "X" }, null, null); foreach (var kv in t1_DummyParamList) { frame.DeducedTemplateParameters[kv.Key] = new TemplateParameterSymbol(t2, dummyType); } var t1_TypeResults = Resolver.TypeResolution.TypeDeclarationResolver.Resolve(Spec, ctxt); if (pop) { ctxt.Pop(); } if (t1_TypeResults == null || t1_TypeResults.Length == 0) { return(true); } // Now try to fit the virtual Type t2 into t1 - and return true if it's possible return(new TemplateParameterDeduction(new DeducedTypeDictionary(), ctxt).Handle(t2, t1_TypeResults[0])); }
/// <summary> /// </summary> /// <param name="ast">The syntax tree to scan</param> /// <param name="symbol">Might not be a child symbol of ast</param> /// <param name="ctxt">The context required to search for symbols</param> /// <returns></returns> public static IEnumerable<ISyntaxRegion> Scan(DModule ast, INode symbol, ResolutionContext ctxt, bool includeDefinition = true) { if (ast == null || symbol == null || ctxt == null) return null; ctxt.PushNewScope(ast); var f = new ReferencesFinder(symbol, ast, ctxt); ast.Accept (f); ctxt.Pop(); var nodeRoot = symbol.NodeRoot as DModule; if (includeDefinition && nodeRoot != null && nodeRoot.FileName == ast.FileName) { var dc = symbol.Parent as DClassLike; if (dc != null && dc.ClassType == D_Parser.Parser.DTokens.Template && dc.NameHash == symbol.NameHash) { f.l.Insert(0, new IdentifierDeclaration(dc.NameHash) { Location = dc.NameLocation, EndLocation = new CodeLocation(dc.NameLocation.Column + dc.Name.Length, dc.NameLocation.Line) }); } f.l.Insert(0, new IdentifierDeclaration(symbol.NameHash) { Location = symbol.NameLocation, EndLocation = new CodeLocation(symbol.NameLocation.Column + symbol.Name.Length, symbol.NameLocation.Line) }); } return f.l; }
/* * public bool WaitForFinish(int millisecondsToWait = -1) * { * if(millisecondsToWait < 0) * return completedEvent.WaitOne(); * return completedEvent.WaitOne(millisecondsToWait); * }*/ public void CacheModuleMethods(DModule ast, ResolutionContext ctxt) { foreach (var m in ast) { if (m is DMethod) { var dm = (DMethod)m; if (dm.Parameters == null || dm.NameHash == 0 || dm.Parameters.Count == 0 || dm.Parameters[0].Type == null) { continue; } ctxt.PushNewScope(dm); var firstArg_result = TypeDeclarationResolver.Resolve(dm.Parameters[0].Type, ctxt); ctxt.Pop(); if (firstArg_result != null && firstArg_result.Length != 0) { CachedMethods[dm] = firstArg_result[0]; } } } }
static AbstractType[] TryGetImplicitProperty(TemplateType template, ResolutionContext ctxt) { // Prepare a new context bool pop = !ctxt.ScopedBlockIsInNodeHierarchy(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 matchingChild = TypeDeclarationResolver.ResolveFurtherTypeIdentifier( template.NameHash, new[]{ template }, ctxt); // Undo context-related changes if (pop) ctxt.Pop(); else ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(template); return matchingChild; }
public static MemberSymbol[] TryResolveUFCS( ISemantic firstArgument, PostfixExpression_Access acc, ResolutionContext ctxt) { if (ctxt == null) { return(null); } int name = 0; if (acc.AccessExpression is IdentifierExpression) { name = ((IdentifierExpression)acc.AccessExpression).ValueStringHash; } else if (acc.AccessExpression is TemplateInstanceExpression) { name = ((TemplateInstanceExpression)acc.AccessExpression).TemplateIdHash; } else { return(null); } var methodMatches = new List <MemberSymbol>(); if (ctxt.ParseCache != null) { foreach (var pc in ctxt.ParseCache) { var tempResults = pc.UfcsCache.FindFitting(ctxt, acc.Location, firstArgument, name); if (tempResults != null) { foreach (var m in tempResults) { ctxt.PushNewScope(m); if (m.TemplateParameters != null && m.TemplateParameters.Length != 0) { var ov = TemplateInstanceHandler.DeduceParamsAndFilterOverloads( new[] { new MemberSymbol(m, null, acc) }, new[] { firstArgument }, true, ctxt); if (ov == null || ov.Length == 0) { continue; } var ms = (DSymbol)ov[0]; ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); } var mr = TypeDeclarationResolver.HandleNodeMatch(m, ctxt, null, acc) as MemberSymbol; if (mr != null) { mr.FirstArgument = firstArgument; mr.DeducedTypes = ctxt.CurrentContext.DeducedTemplateParameters.ToReadonly(); mr.IsUFCSResult = true; methodMatches.Add(mr); } ctxt.Pop(); } } } } return(methodMatches.Count == 0 ? null : methodMatches.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(Evaluation.EvaluateType(returnStmt.ReturnExpression, ctxt)); if (pushMethodScope) ctxt.Pop(); return t; } return new PrimitiveType (DTokens.Void); } return null; }
bool HandleAliasThisDeclarations(TemplateIntermediateType tit, MemberFilter vis) { bool pop; var ch = tit.Definition [DVariable.AliasThisIdentifierHash]; if (ch != null) { foreach (DVariable aliasDef in ch) { if (MatchesCompilationConditions(aliasDef) || aliasDef.Type == null) { continue; } pop = ctxt.ScopedBlock != tit.Definition; if (pop) { ctxt.PushNewScope(tit.Definition); } // Resolve the aliased symbol and expect it to be a member symbol(?). //TODO: Check if other cases are allowed as well! var aliasedSymbol = DResolver.StripAliasSymbol(TypeDeclarationResolver.ResolveSingle(aliasDef.Type, ctxt)); var aliasedMember = aliasedSymbol as MemberSymbol; if (pop) { ctxt.Pop(); } if (aliasedMember == null) { if (aliasedSymbol != null) { ctxt.LogError(aliasDef, "Aliased type from 'alias this' definition is expected to be a type instance, not " + aliasedSymbol.ToString() + "!"); } continue; } /* * The aliased member's type can be everything! */ aliasedSymbol = aliasedMember.Base; foreach (var statProp in StaticProperties.ListProperties(aliasedSymbol)) { if (HandleItem(statProp)) { return(true); } } /** TODO: Visit ufcs recommendations and other things that * become added in e.g. MemberCompletionProvider */ var tit_ = aliasedSymbol as TemplateIntermediateType; if (tit_ != null) { pop = !ctxt.ScopedBlockIsInNodeHierarchy(tit_.Definition); if (pop) { ctxt.PushNewScope(tit_.Definition); } ctxt.CurrentContext.IntroduceTemplateParameterTypes(tit_); var r = DeepScanClass(tit_, vis, true); if (pop) { ctxt.Pop(); } else { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(tit_); } if (r) { return(true); } } } } return(false); }
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> /// 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()); }
/// <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 UserDefinedType ResolveBaseClasses(UserDefinedType tr, ResolutionContext ctxt, bool ResolveFirstBaseIdOnly = false) { if (bcStack > 8) { bcStack--; return(tr); } if (tr is EnumType) { var et = tr as EnumType; AbstractType bt = null; if (et.Definition.Type == null) { bt = new PrimitiveType(DTokens.Int); } else { if (tr.Definition.Parent is IBlockNode) { ctxt.PushNewScope((IBlockNode)tr.Definition.Parent); } var bts = TypeDeclarationResolver.Resolve(et.Definition.Type, ctxt); if (tr.Definition.Parent is IBlockNode) { ctxt.Pop(); } ctxt.CheckForSingleResult(bts, et.Definition.Type); if (bts != null && bts.Length != 0) { bt = bts[0]; } } return(new EnumType(et.Definition, bt, et.DeclarationOrExpressionBase)); } var dc = tr.Definition as DClassLike; // Return immediately if searching base classes of the Object class if (dc == null || ((dc.BaseClasses == null || dc.BaseClasses.Count < 1) && dc.Name == "Object")) { return(tr); } // If no base class(es) specified, and if it's no interface that is handled, return the global Object reference // -- and do not throw any error message, it's ok if (dc.BaseClasses == null || dc.BaseClasses.Count < 1) { if (tr is ClassType) // Only Classes can inherit from non-interfaces { return(new ClassType(dc, tr.DeclarationOrExpressionBase, ctxt.ParseCache.ObjectClassResult)); } return(tr); } #region Base class & interface resolution TemplateIntermediateType baseClass = null; var interfaces = new List <InterfaceType>(); if (!(tr is ClassType || tr is InterfaceType)) { if (dc.BaseClasses.Count != 0) { ctxt.LogError(dc, "Only classes and interfaces may inherit from other classes/interfaces"); } return(tr); } 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 && ((IdentifierDeclaration)type).Id == "Object") { 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.ToString(false) == dc.Name || dc.NodeRoot == dc) { ctxt.LogError(new ResolutionError(dc, "A class cannot inherit from itself")); continue; } ctxt.PushNewScope(dc.Parent as IBlockNode); bcStack++; var 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 (tr is InterfaceType) { ctxt.LogError(new ResolutionError(type, "An interface cannot inherit from non-interfaces")); } else if (i == 0) { baseClass = (TemplateIntermediateType)r; } 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((InterfaceType)r); } else { ctxt.LogError(new ResolutionError(type, "Resolved class is neither a class nor an interface")); continue; } } bcStack--; ctxt.Pop(); } #endregion if (baseClass == null && interfaces.Count == 0) { return(tr); } if (tr is ClassType) { return(new ClassType(dc, tr.DeclarationOrExpressionBase, baseClass, interfaces.Count == 0 ? null : interfaces.ToArray(), tr.DeducedTypes)); } else if (tr is InterfaceType) { return(new InterfaceType(dc, tr.DeclarationOrExpressionBase, interfaces.Count == 0 ? null : interfaces.ToArray(), tr.DeducedTypes)); } // Method should end here return(tr); }
/// <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, ResolutionContext ctxt, AbstractType resultBase = null, ISyntaxRegion typeBase = null, NodeMatchHandleVisitor vis = null) { // See https://github.com/aBothe/Mono-D/issues/161 int stkC; if (stackCalls == null) { stackCalls = new Dictionary <INode, int>(); stackCalls[m] = 1; } else { stackCalls[m] = stackCalls.TryGetValue(m, out stkC) ? ++stkC : 1; } /* * Pushing a new scope is only required if current scope cannot be found in the handled node's hierarchy. * Edit: No, it is required nearly every time because of nested type declarations - then, we do need the * current block scope. */ bool popAfterwards; { var newScope = m is IBlockNode ? (IBlockNode)m : m.Parent as IBlockNode; popAfterwards = ctxt.ScopedBlock != newScope && newScope != null; if (popAfterwards) { var options = ctxt.CurrentContext.ContextDependentOptions; var applyOptions = ctxt.ScopedBlockIsInNodeHierarchy(m); ctxt.PushNewScope(newScope); if (applyOptions) { ctxt.CurrentContext.ContextDependentOptions = options; } } } // To support resolving type parameters to concrete types if the context allows this, introduce all deduced parameters to the current context if (resultBase is DSymbol) { ctxt.CurrentContext.IntroduceTemplateParameterTypes((DSymbol)resultBase); } var ret = m.Accept(vis ?? new NodeMatchHandleVisitor { ctxt = ctxt, resultBase = resultBase, typeBase = typeBase }); if (popAfterwards) { ctxt.Pop(); } else if (resultBase is DSymbol) { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals((DSymbol)resultBase); } stackCalls.TryGetValue(m, out stkC); if (stkC == 1) { stackCalls.Remove(m); } else { stackCalls[m] = stkC - 1; } return(ret); }
/* public bool WaitForFinish(int millisecondsToWait = -1) { if(millisecondsToWait < 0) return completedEvent.WaitOne(); return completedEvent.WaitOne(millisecondsToWait); }*/ public void CacheModuleMethods(DModule ast, ResolutionContext ctxt) { foreach (var m in ast) if (m is DMethod) { var dm = (DMethod)m; if (dm.Parameters == null || dm.NameHash == 0 || dm.Parameters.Count == 0 || dm.Parameters[0].Type == null) continue; ctxt.PushNewScope(dm); var firstArg_result = TypeDeclarationResolver.Resolve(dm.Parameters[0].Type, ctxt); ctxt.Pop(); if (firstArg_result != null && firstArg_result.Length != 0) CachedMethods[dm] = firstArg_result[0]; } }
static void HandleDMethodOverload(ResolutionContext ctxt, bool eval, ISymbolValue baseValue, List <ISemantic> callArguments, bool returnBaseTypeOnly, bool hasNonFinalArgs, List <AbstractType> argTypeFilteredOverloads, ref bool hasHandledUfcsResultBefore, MemberSymbol ms) { var dm = ms.Definition as DMethod; if (dm == null) { return; } ISemantic firstUfcsArg; bool isUfcs = UFCSResolver.IsUfcsResult(ms, out firstUfcsArg); // In the case of an ufcs, insert the first argument into the CallArguments list if (isUfcs && !hasHandledUfcsResultBefore) { callArguments.Insert(0, eval ? baseValue as ISemantic : firstUfcsArg); hasHandledUfcsResultBefore = true; } else if (!isUfcs && hasHandledUfcsResultBefore) // In the rare case of having a ufcs result occuring _after_ a normal member result, remove the initial arg again { callArguments.RemoveAt(0); hasHandledUfcsResultBefore = false; } if (dm.Parameters.Count == 0 && callArguments.Count > 0) { return; } var deducedTypeDict = new DeducedTypeDictionary(ms); var templateParamDeduction = new TemplateParameterDeduction(deducedTypeDict, ctxt); var pop = ctxt.ScopedBlock != dm; if (pop) { ctxt.PushNewScope(dm); ctxt.CurrentContext.DeducedTemplateParameters = deducedTypeDict; } bool add = true; int currentArg = 0; if (dm.Parameters.Count > 0 || callArguments.Count > 0) { for (int i = 0; i < dm.Parameters.Count; i++) { var paramType = dm.Parameters[i].Type; if (!pop) { ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); } // Handle the usage of tuples: Tuples may only be used as as-is, so not as an array, pointer or in a modified way.. if (paramType is IdentifierDeclaration && TryHandleMethodArgumentTuple(ctxt, ref add, callArguments, dm, deducedTypeDict, i, ref currentArg)) { continue; } else if (currentArg < callArguments.Count) { if (!(add = templateParamDeduction.HandleDecl(null, paramType, callArguments[currentArg++]))) { break; } } else { // If there are more parameters than arguments given, check if the param has default values add = !(dm.Parameters[i] is DVariable) || (dm.Parameters[i] as DVariable).Initializer != null; // Assume that all further method parameters do have default values - and don't check further parameters break; } } } if (!add) { if (pop) { ctxt.Pop(); } else { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms); } return; } // If type params were unassigned, try to take the defaults if (dm.TemplateParameters != null) { foreach (var tpar in dm.TemplateParameters) { if (deducedTypeDict[tpar] == null && !templateParamDeduction.Handle(tpar, null)) { if (!hasNonFinalArgs) { if (pop) { ctxt.Pop(); } else { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms); } return; } deducedTypeDict[tpar] = new TemplateParameterSymbol(tpar, null); } } } if (deducedTypeDict.AllParamatersSatisfied || hasNonFinalArgs) { ms.DeducedTypes = deducedTypeDict.ToReadonly(); if (!pop) { ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); } var bt = TypeDeclarationResolver.GetMethodReturnType(dm, ctxt) ?? ms.Base; if (pop) { ctxt.Pop(); } else { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms); } if (eval || !returnBaseTypeOnly) { argTypeFilteredOverloads.Add(new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) { Tag = ms.Tag }); } else { argTypeFilteredOverloads.Add(bt); } } }
/// <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, object 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, bn, 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); ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(udt); if(!pop) ctxt.Pop(); } 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).Definition, nextIdentifierHash, typeIdObject)); else { statProp = StaticProperties.TryEvalPropertyType(ctxt, b, nextIdentifierHash); if (statProp != null) r.Add(statProp); } // TODO: Search for UFCS symbols } return r.Count == 0 ? null : r.ToArray(); }
/// <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, ResolutionContext ctxt, AbstractType resultBase = null, object typeBase = null) { AbstractType ret = null; // See https://github.com/aBothe/Mono-D/issues/161 int stkC; if (stackCalls == null) { stackCalls = new Dictionary <INode, int>(); stackCalls[m] = stkC = 1; } else if (stackCalls.TryGetValue(m, out stkC)) { stackCalls[m] = ++stkC; } else { stackCalls[m] = stkC = 1; } /* * Pushing a new scope is only required if current scope cannot be found in the handled node's hierarchy. * Edit: No, it is required nearly every time because of nested type declarations - then, we do need the * current block scope. */ bool popAfterwards; { var newScope = m is IBlockNode ? (IBlockNode)m : m.Parent as IBlockNode; popAfterwards = ctxt.ScopedBlock != newScope && newScope != null; if (popAfterwards) { var options = ctxt.CurrentContext.ContextDependentOptions; var applyOptions = ctxt.ScopedBlockIsInNodeHierarchy(m); ctxt.PushNewScope(newScope); if (applyOptions) { ctxt.CurrentContext.ContextDependentOptions = options; } } } var canResolveBase = ((ctxt.Options & ResolutionOptions.DontResolveBaseTypes) != ResolutionOptions.DontResolveBaseTypes) && stkC < 10 && (m.Type == null || m.Type.ToString(false) != m.Name); // To support resolving type parameters to concrete types if the context allows this, introduce all deduced parameters to the current context if (resultBase is DSymbol) { ctxt.CurrentContext.IntroduceTemplateParameterTypes((DSymbol)resultBase); } var importSymbolNode = m as ImportSymbolNode; var variable = m as DVariable; // Only import symbol aliases are allowed to search in the parse cache if (importSymbolNode != null) { ret = HandleImportSymbolMatch(importSymbolNode, ctxt); } else if (variable != null) { AbstractType bt = null; if (!(variable is EponymousTemplate)) { if (canResolveBase) { var bts = TypeDeclarationResolver.Resolve(variable.Type, ctxt); ctxt.CheckForSingleResult(bts, variable.Type); 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(Evaluation.EvaluateType(variable.Initializer, ctxt)); } // Check if inside an foreach statement header if (bt == null && ctxt.ScopedStatement != null) { bt = GetForeachIteratorType(variable, ctxt); } } // Note: Also works for aliases! In this case, we simply try to resolve the aliased type, otherwise the variable's base type ret = variable.IsAlias ? new AliasedType(variable, bt, typeBase as ISyntaxRegion) as MemberSymbol : new MemberSymbol(variable, bt, typeBase as ISyntaxRegion); } else { ret = new EponymousTemplateType(variable as EponymousTemplate, GetInvisibleTypeParameters(variable, ctxt).AsReadOnly(), typeBase as ISyntaxRegion); } } else if (m is DMethod) { ret = new MemberSymbol(m as DNode, canResolveBase ? GetMethodReturnType(m as DMethod, ctxt) : null, typeBase as ISyntaxRegion); } else if (m is DClassLike) { ret = HandleClassLikeMatch(m as DClassLike, ctxt, typeBase, canResolveBase); } else if (m is DModule) { var mod = (DModule)m; if (typeBase != null && typeBase.ToString() != mod.ModuleName) { var pack = ctxt.ParseCache.LookupPackage(typeBase.ToString()).FirstOrDefault(); 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 TemplateParameter.Node) { //ResolveResult[] templateParameterType = null; //TODO: Resolve the specialization type //var templateParameterType = TemplateInstanceHandler.ResolveTypeSpecialization(tmp, ctxt); ret = new TemplateParameterSymbol((m as TemplateParameter.Node).TemplateParameter, null, typeBase as ISyntaxRegion); } else if (m is NamedTemplateMixinNode) { var tmxNode = m as NamedTemplateMixinNode; ret = new MemberSymbol(tmxNode, canResolveBase ? ResolveSingle(tmxNode.Type, ctxt) : null, typeBase as ISyntaxRegion); } if (popAfterwards) { ctxt.Pop(); } else if (resultBase is DSymbol) { ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals((DSymbol)resultBase); } if (stkC == 1) { stackCalls.Remove(m); } else { stackCalls[m] = stkC - 1; } return(ret); }
/// <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(int nextIdentifierHash, IEnumerable <AbstractType> resultBases, ResolutionContext ctxt, object 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, bn, 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); } ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(udt); if (!pop) { ctxt.Pop(); } } 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).Definition, nextIdentifierHash, typeIdObject)); } else { statProp = StaticProperties.TryEvalPropertyType(ctxt, b, nextIdentifierHash); if (statProp != null) { r.Add(statProp); } } // TODO: Search for UFCS symbols } return(r.Count == 0 ? null : r.ToArray()); }
/// <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, ResolutionContext ctxt, AbstractType resultBase = null, object typeBase = null) { AbstractType ret = null; // See https://github.com/aBothe/Mono-D/issues/161 int stkC; if (stackCalls == null) { stackCalls = new Dictionary<INode, int>(); stackCalls[m] = stkC = 1; } else if (stackCalls.TryGetValue(m, out stkC)) stackCalls[m] = ++stkC; else stackCalls[m] = stkC = 1; /* * Pushing a new scope is only required if current scope cannot be found in the handled node's hierarchy. * Edit: No, it is required nearly every time because of nested type declarations - then, we do need the * current block scope. */ bool popAfterwards; { var newScope = m is IBlockNode ? (IBlockNode)m : m.Parent as IBlockNode; popAfterwards = ctxt.ScopedBlock != newScope && newScope != null; if (popAfterwards) { var options = ctxt.CurrentContext.ContextDependentOptions; var applyOptions = ctxt.ScopedBlockIsInNodeHierarchy (m); ctxt.PushNewScope (newScope); if (applyOptions) ctxt.CurrentContext.ContextDependentOptions = options; } } var canResolveBase = ((ctxt.Options & ResolutionOptions.DontResolveBaseTypes) != ResolutionOptions.DontResolveBaseTypes) && stkC < 10 && (m.Type == null || m.Type.ToString(false) != m.Name); // To support resolving type parameters to concrete types if the context allows this, introduce all deduced parameters to the current context if (resultBase is DSymbol) ctxt.CurrentContext.IntroduceTemplateParameterTypes((DSymbol)resultBase); var importSymbolNode = m as ImportSymbolNode; var variable = m as DVariable; // Only import symbol aliases are allowed to search in the parse cache if (importSymbolNode != null) ret = HandleImportSymbolMatch (importSymbolNode,ctxt); else if (variable != null) { AbstractType bt = null; if (!(variable is EponymousTemplate)) { if (canResolveBase) { var bts = TypeDeclarationResolver.Resolve (variable.Type, ctxt); ctxt.CheckForSingleResult (bts, variable.Type); 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 (Evaluation.EvaluateType (variable.Initializer, ctxt)); } // Check if inside an foreach statement header if (bt == null && ctxt.ScopedStatement != null) bt = GetForeachIteratorType (variable, ctxt); } // Note: Also works for aliases! In this case, we simply try to resolve the aliased type, otherwise the variable's base type ret = variable.IsAlias ? new AliasedType (variable, bt, typeBase as ISyntaxRegion) as MemberSymbol : new MemberSymbol (variable, bt, typeBase as ISyntaxRegion); } else ret = new EponymousTemplateType (variable as EponymousTemplate, GetInvisibleTypeParameters(variable, ctxt).AsReadOnly(), typeBase as ISyntaxRegion); } else if (m is DMethod) { ret = new MemberSymbol(m as DNode,canResolveBase ? GetMethodReturnType(m as DMethod, ctxt) : null, typeBase as ISyntaxRegion); } else if (m is DClassLike) ret = HandleClassLikeMatch (m as DClassLike, ctxt, typeBase, canResolveBase); else if (m is DModule) { var mod = (DModule)m; if (typeBase != null && typeBase.ToString() != mod.ModuleName) { var pack = ctxt.ParseCache.LookupPackage(typeBase.ToString()).FirstOrDefault(); 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 TemplateParameter.Node) { //ResolveResult[] templateParameterType = null; //TODO: Resolve the specialization type //var templateParameterType = TemplateInstanceHandler.ResolveTypeSpecialization(tmp, ctxt); ret = new TemplateParameterSymbol((m as TemplateParameter.Node).TemplateParameter, null, typeBase as ISyntaxRegion); } else if(m is NamedTemplateMixinNode) { var tmxNode = m as NamedTemplateMixinNode; ret = new MemberSymbol(tmxNode, canResolveBase ? ResolveSingle(tmxNode.Type, ctxt) : null, typeBase as ISyntaxRegion); } if (popAfterwards) ctxt.Pop(); else if (resultBase is DSymbol) ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals((DSymbol)resultBase); if (stkC == 1) stackCalls.Remove(m); else stackCalls[m] = stkC-1; return ret; }