static AbstractType DeduceEponymousTemplate(EponymousTemplateType ept, ResolutionContext ctxt) { if (ept.Definition.Initializer == null && ept.Definition.Type == null) { ctxt.LogError(ept.Definition, "Can't deduce type from empty initializer!"); return(null); } // Introduce the deduced params to the current resolution context ctxt.CurrentContext.IntroduceTemplateParameterTypes(ept); // Get actual overloads AbstractType deducedType = null; var def = ept.Definition; deducedType = new MemberSymbol(def, def.Type != null ? TypeDeclarationResolver.ResolveSingle(def.Type, ctxt) : ExpressionTypeEvaluation.EvaluateType(def.Initializer, ctxt), null, ept.DeducedTypes); //ept; //ExpressionTypeEvaluation.EvaluateType (ept.Definition.Initializer, ctxt); deducedType.Tag = ept.Tag; // Currently requried for proper UFCS resolution - sustain ept's Tag // Undo context-related changes ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ept); return(deducedType); }
void HandleMethod(DMethod dm, MemberSymbol alreadyResolvedMethod = null) { if (dm != null && dm.Parameters.Count > 0 && dm.Parameters[0].Type != null) { var pop = ctxt.ScopedBlock != dm; if (pop) { ctxt.PushNewScope(dm); } var t = TypeDeclarationResolver.ResolveSingle(dm.Parameters [0].Type, ctxt); if (ResultComparer.IsImplicitlyConvertible(firstArgument, t, ctxt)) { var res = alreadyResolvedMethod ?? new MemberSymbol(dm, null, sr); res.Tag = new UfcsTag { firstArgument = firstArgument }; matches.Add(res); } if (pop) { ctxt.Pop(); } } }
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)); }
static AbstractType[] TryGetImplicitProperty(TemplateType template, ResolutionContext ctxt) { // Get actual overloads var matchingChild = TypeDeclarationResolver.ResolveFurtherTypeIdentifier(template.NameHash, new[] { template }, ctxt, template.DeclarationOrExpressionBase, false); 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; } } return(matchingChild); }
protected override bool HandleItem(INode n) { if (ctxt.CancelOperation) { return(true); } if ((nameFilterHash != 0 && n.NameHash != nameFilterHash) || (!(n is ImportSymbolNode) && !(n.Parent is DModule))) { return(false); } DSymbol ds; 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); foreach (var ov in AmbiguousType.TryDissolve(t)) { ds = ov as DSymbol; if (ds is MemberSymbol && ds.Definition is DMethod) { HandleMethod(ds.Definition as DMethod, ov as MemberSymbol); } else if (ds != null && (dc = ds.Definition as DClassLike) != null && dc.ClassType == DTokens.Template) { if (sr is TemplateInstanceExpression || nameFilterHash == 0) { ds.Tag = new UfcsTag { firstArgument = firstArgument }; matches.Add(ds); } } // Perhaps other types may occur here as well - but which remain then to be added? } } return(false); }
public static List <ISemantic> PreResolveTemplateArgs(TemplateInstanceExpression tix, ResolverContextStack ctxt) { // 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 { templateArguments.Add(res[0]); } } } else { templateArguments.Add(Evaluation.EvaluateValue(arg, ctxt)); } } } return(templateArguments); }
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); }
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); } } }
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)); }
void HandleMethod(DMethod dm, MemberSymbol alreadyResolvedMethod = null) { if (dm != null && dm.Parameters.Count > 0 && dm.Parameters[0].Type != null) { var loc = dm.Body != null ? dm.Body.Location : dm.Location; using (alreadyResolvedMethod != null ? ctxt.Push(alreadyResolvedMethod, loc) : ctxt.Push(dm, loc)) { var t = TypeDeclarationResolver.ResolveSingle(dm.Parameters[0].Type, ctxt); if (ResultComparer.IsImplicitlyConvertible(firstArgument, t, ctxt)) { var res = alreadyResolvedMethod ?? TypeDeclarationResolver.HandleNodeMatch(dm, ctxt, typeBase: sr); res.Tag = new UfcsTag { firstArgument = firstArgument }; matches.Add(res); } } } }
public static AbstractType[] ResolveType(IEditorData editor, ResolverContextStack ctxt, AstReparseOptions Options = 0) { if (ctxt == null) { return(null); } var o = GetScopedCodeObject(editor, ctxt, Options); if (o is IExpression) { return(Evaluation.EvaluateTypes((IExpression)o, ctxt)); } else if (o is ITypeDeclaration) { return(TypeDeclarationResolver.Resolve((ITypeDeclaration)o, ctxt)); } else { return(null); } }
public static AbstractType[] ResolveType(IEditorData editor, ResolutionContext ctxt = null) { if (ctxt == null) { ctxt = ResolutionContext.Create(editor); } var o = GetScopedCodeObject(editor); var optionBackup = ctxt.CurrentContext.ContextDependentOptions; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.ReturnMethodReferencesOnly; AbstractType[] ret; if (o is IExpression) { ret = ExpressionTypeEvaluation.EvaluateTypes((IExpression)o, ctxt); } else if (o is ITypeDeclaration) { ret = TypeDeclarationResolver.Resolve((ITypeDeclaration)o, ctxt); } else if (o is INode) { ret = new[] { TypeDeclarationResolver.HandleNodeMatch(o as INode, ctxt) } } ; else { ret = null; } ctxt.CurrentContext.ContextDependentOptions = optionBackup; return(ret); }
public static AbstractType ResolveType(IEditorData editor, ResolutionContext ctxt = null) { var o = GetScopedCodeObject(editor); if (ctxt == null) { ctxt = ResolutionContext.Create(editor, false); } AbstractType ret = null; CodeCompletion.DoTimeoutableCompletionTask(null, ctxt, () => { ctxt.Push(editor); var optionBackup = ctxt.CurrentContext.ContextDependentOptions; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.ReturnMethodReferencesOnly; if (o is IExpression) { ret = ExpressionTypeEvaluation.EvaluateType((IExpression)o, ctxt, false); } else if (o is ITypeDeclaration) { ret = TypeDeclarationResolver.ResolveSingle((ITypeDeclaration)o, ctxt); } else if (o is INode) { ret = TypeDeclarationResolver.HandleNodeMatch(o as INode, ctxt); } ctxt.CurrentContext.ContextDependentOptions = optionBackup; }); return(ret); }
public static MemberSymbol[] TryResolveUFCS( ISemantic firstArgument, PostfixExpression_Access acc, ResolverContextStack ctxt) { if (ctxt == null) { return(null); } var name = ""; if (acc.AccessExpression is IdentifierExpression) { name = ((IdentifierExpression)acc.AccessExpression).Value as string; } else if (acc.AccessExpression is TemplateInstanceExpression) { name = ((TemplateInstanceExpression)acc.AccessExpression).TemplateIdentifier.Id; } 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; ctxt.Pop(); if (mr != null) { mr.IsUFCSResult = true; methodMatches.Add(mr); } } } } } return(methodMatches.Count == 0 ? null : methodMatches.ToArray()); }
private static List <AbstractType> DeduceOverloads( IEnumerable <AbstractType> rawOverloadList, IEnumerable <ISemantic> givenTemplateArguments, bool isMethodCall, ResolutionContext ctxt) { bool hasTemplateArgsPassed = givenTemplateArguments != null && givenTemplateArguments.FirstOrDefault() != null; var filteredOverloads = new List <AbstractType>(); if (rawOverloadList == null) { return(filteredOverloads); } foreach (var o in rawOverloadList) { var overload = o as DSymbol; while (overload is TemplateParameterSymbol) { overload = overload.Base as DSymbol; } if (overload == null) { if (!hasTemplateArgsPassed) { filteredOverloads.Add(o); } continue; } else if (overload.Tag is TypeDeclarationResolver.AliasTag && (hasTemplateArgsPassed || !(overload.DeclarationOrExpressionBase is TemplateInstanceExpression))) { TypeDeclarationResolver.ResetDeducedSymbols(overload); } var tplNode = overload.Definition; // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params if (tplNode == null) { filteredOverloads.Add(o); continue; } bool ignoreOtherOverloads; var hook = D_Parser.Resolver.ResolutionHooks.HookRegistry.TryDeduce(overload, givenTemplateArguments, out ignoreOtherOverloads); if (hook != null) { filteredOverloads.Add(hook); if (ignoreOtherOverloads) { break; } 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(o); } continue; } var deducedTypes = new DeducedTypeDictionary(overload); if (deducedTypes.AllParamatersSatisfied) // Happens e.g. after resolving a class/interface definition { filteredOverloads.Add(o); } else if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes)) { overload.DeducedTypes = deducedTypes.ToReadonly(); // Assign calculated types to final result filteredOverloads.Add(o); } else { overload.DeducedTypes = null; } } return(filteredOverloads); }
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); }
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); }
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); }
public static AbstractType ResolveTypeLoosely(IEditorData editor, out NodeResolutionAttempt resolutionAttempt, ResolutionContext ctxt = null) { var o = GetScopedCodeObject(editor); if (ctxt == null) { ctxt = ResolutionContext.Create(editor, false); } AbstractType ret = null; NodeResolutionAttempt resAttempt = NodeResolutionAttempt.Normal; CodeCompletion.DoTimeoutableCompletionTask(null, ctxt, () => { ctxt.Push(editor); var optionBackup = ctxt.CurrentContext.ContextDependentOptions; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.ReturnMethodReferencesOnly | ResolutionOptions.DontResolveAliases; if (o is IExpression) { ret = ExpressionTypeEvaluation.EvaluateType((IExpression)o, ctxt, false); } else if (o is ITypeDeclaration) { ret = TypeDeclarationResolver.ResolveSingle((ITypeDeclaration)o, ctxt); } else if (o is INode) { ret = TypeDeclarationResolver.HandleNodeMatch(o as INode, ctxt, null, o); } else { ret = null; } if (ret == null) { resAttempt = NodeResolutionAttempt.NoParameterOrTemplateDeduction; if (o is PostfixExpression_MethodCall) { o = (o as PostfixExpression_MethodCall).PostfixForeExpression; } ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.NoTemplateParameterDeduction | ResolutionOptions.DontResolveAliases; if (o is IdentifierExpression) { ret = AmbiguousType.Get(ExpressionTypeEvaluation.GetOverloads(o as IdentifierExpression, ctxt, deduceParameters: false), o); } else if (o is ITypeDeclaration) { ret = TypeDeclarationResolver.ResolveSingle(o as ITypeDeclaration, ctxt); } else if (o is IExpression) { ret = ExpressionTypeEvaluation.EvaluateType(o as IExpression, ctxt, false); } } if (ret == null) { resAttempt = NodeResolutionAttempt.RawSymbolLookup; var overloads = TypeDeclarationResolver.HandleNodeMatches(LookupIdRawly(editor, o as ISyntaxRegion), ctxt, null, o); ret = AmbiguousType.Get(overloads, o); } ctxt.CurrentContext.ContextDependentOptions = optionBackup; }); resolutionAttempt = resAttempt; if (ret != null) { ret.DeclarationOrExpressionBase = o; } 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 UserDefinedType ResolveBaseClasses(UserDefinedType tr, ResolverContextStack 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 = 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, 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> /// 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)); }
public static AbstractType[] ResolveTypeLoosely(IEditorData editor, out NodeResolutionAttempt resolutionAttempt, ResolutionContext ctxt = null) { if (ctxt == null) { ctxt = ResolutionContext.Create(editor); } var o = GetScopedCodeObject(editor); var optionBackup = ctxt.CurrentContext.ContextDependentOptions; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.ReturnMethodReferencesOnly; resolutionAttempt = NodeResolutionAttempt.Normal; AbstractType[] ret; if (o is IExpression) { ret = ExpressionTypeEvaluation.EvaluateTypes((IExpression)o, ctxt); } else if (o is ITypeDeclaration) { ret = TypeDeclarationResolver.Resolve((ITypeDeclaration)o, ctxt); } else if (o is INode) { ret = new[] { TypeDeclarationResolver.HandleNodeMatch(o as INode, ctxt, null, o) } } ; else { ret = null; } if (ret == null) { resolutionAttempt = NodeResolutionAttempt.NoParameterOrTemplateDeduction; if (o is PostfixExpression_MethodCall) { o = (o as PostfixExpression_MethodCall).PostfixForeExpression; } ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.NoTemplateParameterDeduction; if (o is IdentifierExpression) { ret = ExpressionTypeEvaluation.GetOverloads(o as IdentifierExpression, ctxt, deduceParameters: false); } else if (o is ITypeDeclaration) { ret = TypeDeclarationResolver.Resolve(o as ITypeDeclaration, ctxt); } else if (o is IExpression) { ret = ExpressionTypeEvaluation.EvaluateTypes(o as IExpression, ctxt); } } if (ret == null) { resolutionAttempt = NodeResolutionAttempt.RawSymbolLookup; ret = TypeDeclarationResolver.HandleNodeMatches(LookupIdRawly(editor, o as ISyntaxRegion), ctxt, null, o); } if (ret != null) { foreach (var r in ret) { if (r != null) { r.DeclarationOrExpressionBase = o; } } } ctxt.CurrentContext.ContextDependentOptions = optionBackup; return(ret); }