public static AbstractType[] ResolveType(IEditorData editor, AstReparseOptions Options = AstReparseOptions.AlsoParseBeyondCaret, ResolutionContext ctxt = null) { if (ctxt == null) { ctxt = ResolutionContext.Create(editor); } var o = GetScopedCodeObject(editor, Options, ctxt); var optionBackup = ctxt.CurrentContext.ContextDependentOptions; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.ReturnMethodReferencesOnly; AbstractType[] ret; if (o is IExpression) { ret = Evaluation.EvaluateTypes((IExpression)o, ctxt); } else if (o is ITypeDeclaration) { ret = TypeDeclarationResolver.Resolve((ITypeDeclaration)o, ctxt); } else { ret = null; } ctxt.CurrentContext.ContextDependentOptions = optionBackup; return(ret); }
public static AbstractType[] ResolveTypeLoosely(IEditorData editor, out NodeResolutionAttempt resolutionAttempt, ResolutionContext ctxt = null) { if (ctxt == null) { ctxt = ResolutionContext.Create(editor); } var o = GetScopedCodeObject(editor, ctxt: ctxt); var optionBackup = ctxt.CurrentContext.ContextDependentOptions; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.ReturnMethodReferencesOnly; resolutionAttempt = NodeResolutionAttempt.Normal; AbstractType[] ret; if (o is IExpression) { ret = Evaluation.EvaluateTypes((IExpression)o, ctxt); } else if (o is ITypeDeclaration) { ret = TypeDeclarationResolver.Resolve((ITypeDeclaration)o, ctxt); } else { ret = null; } if (ret == null) { resolutionAttempt = NodeResolutionAttempt.NoParameterOrTemplateDeduction; if (o is PostfixExpression_MethodCall) { o = (o as PostfixExpression_MethodCall).PostfixForeExpression; } if (o is IdentifierExpression) { ret = Evaluation.GetOverloads(o as IdentifierExpression, ctxt, false); } else if (o is ITypeDeclaration) { ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.NoTemplateParameterDeduction; ret = TypeDeclarationResolver.Resolve(o as ITypeDeclaration, ctxt); } } if (ret == null) { resolutionAttempt = NodeResolutionAttempt.RawSymbolLookup; ret = TypeDeclarationResolver.HandleNodeMatches(LookupIdRawly(editor, o as ISyntaxRegion), ctxt); } ctxt.CurrentContext.ContextDependentOptions = optionBackup; return(ret); }
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); if (ctxt.CheckForSingleResult(res, tde.Declaration) || res != null) { 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 == null ? (ISemantic)mr : eval); } else { if (!hasNonFinalArgument) { hasNonFinalArgument = IsNonFinalArgument(res[0]); } templateArguments.Add(res[0]); } } } else { var 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); } templateArguments.Add(v); } } } return(templateArguments); }
/// <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); }
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); }
/// <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); }