bool HandleDecl(TemplateTypeParameter p, IdentifierDeclaration id, ISemantic r) { // Bottom-level reached if (id.InnerDeclaration == null && Contains(id.IdHash) && !id.ModuleScoped) { // Associate template param with r return(Set((p != null && id.IdHash == p.NameHash) ? p : null, r, id.IdHash)); } var deducee = DResolver.StripMemberSymbols(AbstractType.Get(r)) as DSymbol; if (id.InnerDeclaration != null && deducee != null && deducee.Definition.NameHash == id.IdHash) { var physicalParentType = TypeDeclarationResolver.HandleNodeMatch(deducee.Definition.Parent, ctxt, null, id.InnerDeclaration); if (HandleDecl(p, id.InnerDeclaration, physicalParentType)) { if (Contains(id.IdHash)) { Set((p != null && id.IdHash == p.NameHash) ? p : null, deducee, id.IdHash); } return(true); } } /* * If not stand-alone identifier or is not required as template param, resolve the id and compare it against r */ var _r = TypeDeclarationResolver.ResolveSingle(id, ctxt); return(_r != null && (EnforceTypeEqualityWhenDeducing ? ResultComparer.IsEqual(r, _r) : ResultComparer.IsImplicitlyConvertible(r, _r))); }
/// <summary> /// Returns false if the item has already been set before and if the already set item is not equal to 'r'. /// Inserts 'r' into the target dictionary and returns true otherwise. /// </summary> bool Set(ITemplateParameter p, ISemantic r, string name = null) { if (string.IsNullOrEmpty(name)) { name = p.Name; } TemplateParameterSymbol rl = null; if (!TargetDictionary.TryGetValue(name, out rl) || rl == null) { TargetDictionary[name] = new TemplateParameterSymbol(p, r, null, TargetDictionary.ParameterOwner); return(true); } else { if (rl != null) { if (ResultComparer.IsEqual(rl.Base, r)) { return(true); } else { // Error: Ambiguous assignment } } TargetDictionary[name] = new TemplateParameterSymbol(p, r, null, TargetDictionary.ParameterOwner); return(false); } }
/// <summary> /// Returns false if the item has already been set before and if the already set item is not equal to 'r'. /// Inserts 'r' into the target dictionary and returns true otherwise. /// </summary> bool Set(TemplateParameter p, ISemantic r, int nameHash) { if (p == null) { if (nameHash != 0 && TargetDictionary.ExpectedParameters != null) { foreach (var tpar in TargetDictionary.ExpectedParameters) { if (tpar.NameHash == nameHash) { p = tpar; break; } } } } if (p == null) { ctxt.LogError(null, "no fitting template parameter found!"); return(false); } // void call(T)(T t) {} // call(myA) -- T is *not* myA but A, so only assign myA's type to T. if (p is TemplateTypeParameter) { var newR = Resolver.TypeResolution.DResolver.StripMemberSymbols(AbstractType.Get(r)); if (newR != null) { r = newR; } } TemplateParameterSymbol rl; if (!TargetDictionary.TryGetValue(p, out rl) || rl == null) { TargetDictionary[p] = new TemplateParameterSymbol(p, r); return(true); } else { if (ResultComparer.IsEqual(rl.Base, r)) { TargetDictionary[p] = new TemplateParameterSymbol(p, r); return(true); } else if (rl == null) { TargetDictionary[p] = new TemplateParameterSymbol(p, r); } // Error: Ambiguous assignment return(false); } }
private bool evalIsExpression_NoAlias(IsExpression isExpression, AbstractType typeToCheck) { if (isExpression.TypeSpecialization != null) { var spec = DResolver.StripAliasSymbols(TypeDeclarationResolver.Resolve(isExpression.TypeSpecialization, ctxt)); return(spec != null && spec.Length != 0 && (isExpression.EqualityTest ? ResultComparer.IsEqual(typeToCheck, spec[0]) : ResultComparer.IsImplicitlyConvertible(typeToCheck, spec[0], ctxt))); } return(isExpression.EqualityTest && evalIsExpression_EvalSpecToken(isExpression, typeToCheck, false).Item1); }
bool HandleDecl(TemplateTypeParameter p, IdentifierDeclaration id, ISemantic r) { // Bottom-level reached if (id.InnerDeclaration == null && Contains(id.Id) && !id.ModuleScoped) { // Associate template param with r return(Set(p, r, id.Id)); } /* * If not stand-alone identifier or is not required as template param, resolve the id and compare it against r */ var _r = TypeDeclarationResolver.Resolve(id, ctxt); ctxt.CheckForSingleResult(_r, id); return(_r != null && _r.Length != 0 && (EnforceTypeEqualityWhenDeducing ? ResultComparer.IsEqual(r, _r[0]) : ResultComparer.IsImplicitlyConvertible(r, _r[0]))); }
internal static bool TryHandleMethodArgumentTuple(ResolutionContext ctxt, ref bool add, List <ISemantic> callArguments, DMethod dm, DeducedTypeDictionary deducedTypeDict, int currentParameter, ref int currentArg) { // .. so only check if it's an identifer & if the id represents a tuple parameter var id = dm.Parameters[currentParameter].Type as IdentifierDeclaration; var curNode = dm as DNode; TemplateParameter tpar = null; while (curNode != null && !curNode.TryGetTemplateParameter(id.IdHash, out tpar)) { curNode = curNode.Parent as DNode; } if (!(tpar is TemplateTupleParameter)) { return(false); } int lastArgumentToTake = -1; /* * Note: an expression tuple parameter can occur also somewhere in between the parameter list! * void write(A...)(bool b, A a, double d) {} * * can be matched by * write(true, 1.2) as well as * write(true, "asdf", 1.2) as well as * write(true, 123, true, 'c', [3,4,5], 3.4) ! */ TemplateParameterSymbol tps; DTuple tuple = null; if (deducedTypeDict.TryGetValue(tpar, out tps) && tps != null) { if (tps.Base is DTuple) { tuple = tps.Base as DTuple; lastArgumentToTake = currentParameter + (tuple.Items == null ? 0 : (tuple.Items.Length - 1)); } else { // Error: Type param must be tuple! } } // - Get the (amount of) arguments that shall be put into the tuple else if (currentParameter == dm.Parameters.Count - 1) { // The usual case: A tuple of a variable length is put at the end of a parameter list.. // take all arguments from i until the end of the argument list.. // ; Also accept empty tuples lastArgumentToTake = callArguments.Count - 1; } else { // Get the type of the next expected parameter var nextExpectedParameter = DResolver.StripMemberSymbols(TypeDeclarationResolver.ResolveSingle(dm.Parameters[currentParameter + 1].Type, ctxt)); // Look for the first argument whose type is equal to the next parameter's type.. for (int k = currentArg; k < callArguments.Count; k++) { if (ResultComparer.IsEqual(AbstractType.Get(callArguments[k]), nextExpectedParameter)) { // .. and assume the tuple to go from i to the previous argument.. lastArgumentToTake = k - 1; break; } } } int argCountToHandle = lastArgumentToTake - currentArg + 1; if (tuple != null) { // - If there's been set an explicit type tuple, compare all arguments' types with those in the tuple if (tuple.Items != null) { foreach (ISemantic item in tuple.Items) { if (currentArg >= callArguments.Count || !ResultComparer.IsImplicitlyConvertible(callArguments[currentArg++], AbstractType.Get(item), ctxt)) { add = false; return(true); } } } } else { // - If there was no explicit initialization, put all arguments' types into a type tuple var argsToTake = new ISemantic[argCountToHandle]; callArguments.CopyTo(currentArg, argsToTake, 0, argsToTake.Length); currentArg += argsToTake.Length; var tt = new DTuple(null, argsToTake); tps = new TemplateParameterSymbol(tpar, tt); // and set the actual template tuple parameter deduction deducedTypeDict[tpar] = tps; } add = true; return(true); }
public static DNode ExamTraceSymbol(string symName, ResolutionContext ctxt, out bool mightBeLegalUnresolvableSymbol) { DSymbol ds = null; mightBeLegalUnresolvableSymbol = false; if (string.IsNullOrWhiteSpace(symName)) { return(null); } // Try to handle a probably mangled string or C function. if (symName.StartsWith("_")) { try{ ds = Demangler.DemangleAndResolve(symName, ctxt) as DSymbol; }catch {} } // Stuff like void std.stdio.File.LockingTextWriter.put!(immutable(char)[]).put(immutable(char)[]) if (ds == null && Lexer.IsIdentifierPart((int)symName[0])) { mightBeLegalUnresolvableSymbol = true; ITypeDeclaration q; var method = DParser.ParseMethodDeclarationHeader(symName, out q); q = Demangler.RemoveNestedTemplateRefsFromQualifier(q); method.Type = Demangler.RemoveNestedTemplateRefsFromQualifier(method.Type); var methodType = TypeDeclarationResolver.GetMethodReturnType(method, ctxt); var methodParameters = new List <AbstractType>(); if (method.Parameters != null && method.Parameters.Count != 0) { foreach (var parm in method.Parameters) { methodParameters.Add(TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(parm.Type), ctxt)); } } ctxt.ContextIndependentOptions |= ResolutionOptions.IgnoreAllProtectionAttributes; var overloads = TypeDeclarationResolver.Resolve(q, ctxt); if (overloads == null || overloads.Length == 0) { return(null); } else if (overloads.Length == 1) { ds = overloads[0] as DSymbol; } else { foreach (var o in overloads) { ds = o as DSymbol; if (ds == null || !(ds.Definition is DMethod)) { continue; } var dm = ds.Definition as DMethod; // Compare return types if (dm.Type != null) { if (methodType == null || ds.Base == null || !ResultComparer.IsEqual(methodType, ds.Base)) { continue; } } else if (dm.Type == null && methodType != null) { return(null); } // Compare parameters if (methodParameters.Count != dm.Parameters.Count) { continue; } for (int i = 0; i < methodParameters.Count; i++) { if (!ResultComparer.IsImplicitlyConvertible(methodParameters[i], TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(dm.Parameters[i].Type), ctxt))) { continue; } } } } } if (ds != null) { return(ds.Definition); } return(null); }
ISymbolValue EvalConcatenation(CatExpression x, ISymbolValue lValue) { // In the (not unusual) case that more than 2 arrays/strings shall be concat'ed - process them more efficiently var catQueue = new Queue <ISymbolValue>(); var catEx = (x as CatExpression); catQueue.Enqueue(lValue); catEx = catEx.RightOperand as CatExpression; ISymbolValue r; while (catEx != null) { r = TryGetValue(E(catEx.LeftOperand)); if (r == null) { EvalError(catEx.LeftOperand, "Couldn't be evaluated."); return(null); } catQueue.Enqueue(r); if (catEx.RightOperand is CatExpression) { catEx = catEx.RightOperand as CatExpression; } else { break; } } r = TryGetValue(E((catEx ?? x).RightOperand)); if (r == null) { EvalError(catEx.LeftOperand, "Couldn't be evaluated."); return(null); } catQueue.Enqueue(r); // Notable: If one element is of the value type of the array, the element is added (either at the front or at the back) to the array // myString ~ 'a' will append an 'a' to the string // 'a' ~ myString inserts 'a' at index 0 // Determine whether we have to build up a string OR a normal list of atomic elements bool isString = true; ArrayType lastArrayType = null; foreach (var e in catQueue) { if (e is AssociativeArrayValue) { EvalError(x, "Can't concatenate associative arrays", e); return(null); } else if (e is ArrayValue) { if (lastArrayType != null && !ResultComparer.IsEqual(lastArrayType, e.RepresentedType)) { EvalError(x, "Both arrays must be of same type", new[] { lastArrayType, e.RepresentedType }); return(null); } lastArrayType = e.RepresentedType as ArrayType; if ((e as ArrayValue).IsString) { continue; } } else if (e is PrimitiveValue) { var btt = (e as PrimitiveValue).BaseTypeToken; if (btt == DTokens.Char || btt == DTokens.Dchar || btt == DTokens.Wchar) { continue; } } isString = false; } if (lastArrayType == null) { EvalError(x, "At least one operand must be an (non-associative) array. If so, the other operand must be of the array's element type.", catQueue.ToArray()); return(null); } if (isString) { var sb = new StringBuilder(); while (catQueue.Count != 0) { var e = catQueue.Dequeue(); if (e is ArrayValue) { sb.Append((e as ArrayValue).StringValue); } else if (e is PrimitiveValue) { sb.Append((char)((e as PrimitiveValue).Value)); } } return(new ArrayValue(GetStringType(LiteralSubformat.Utf8), sb.ToString())); } var elements = new List <ISymbolValue>(); while (catQueue.Count != 0) { var e = catQueue.Dequeue(); var av = e as ArrayValue; if (av != null) { if (av.IsString) { elements.Add(av); } else if (av.Elements != null) { elements.AddRange(av.Elements); } continue; } if (!ResultComparer.IsImplicitlyConvertible(e.RepresentedType, lastArrayType.ValueType, ctxt)) { EvalError(x, "Element with type " + e.RepresentedType.ToCode() + " doesn't fit into array with type " + lastArrayType.ToCode(), catQueue.ToArray()); return(null); } elements.Add(e); } return(new ArrayValue(lastArrayType, elements.ToArray())); }
/// <summary> /// Item1 - True, if isExpression returns true /// Item2 - If Item1 is true, it contains the type of the alias that is defined in the isExpression /// </summary> private Tuple <bool, AbstractType> evalIsExpression_EvalSpecToken(IsExpression isExpression, AbstractType typeToCheck, bool DoAliasHandling = false) { bool r = false; AbstractType res = null; switch (isExpression.TypeSpecializationToken) { /* * To handle semantic tokens like "return" or "super" it's just needed to * look into the current resolver context - * then, we'll be able to gather either the parent method or the currently scoped class definition. */ case DTokens.Struct: case DTokens.Union: case DTokens.Class: case DTokens.Interface: if (r = typeToCheck is UserDefinedType && ((TemplateIntermediateType)typeToCheck).Definition.ClassType == isExpression.TypeSpecializationToken) { res = typeToCheck; } break; case DTokens.Enum: if (!(typeToCheck is EnumType)) { break; } { var tr = (UserDefinedType)typeToCheck; r = true; res = tr.Base; } break; case DTokens.Function: case DTokens.Delegate: if (typeToCheck is DelegateType) { var isFun = false; var dgr = (DelegateType)typeToCheck; if (!dgr.IsFunctionLiteral) { r = isExpression.TypeSpecializationToken == ( (isFun = ((DelegateDeclaration)dgr.DeclarationOrExpressionBase).IsFunction) ? DTokens.Function : DTokens.Delegate); } // Must be a delegate otherwise else { isFun = !(r = isExpression.TypeSpecializationToken == DTokens.Delegate); } if (r) { //TODO if (isFun) { // TypeTuple of the function parameter types. For C- and D-style variadic functions, only the non-variadic parameters are included. // For typesafe variadic functions, the ... is ignored. } else { // the function type of the delegate } } } else // Normal functions are also accepted as delegates { r = isExpression.TypeSpecializationToken == DTokens.Delegate && typeToCheck is MemberSymbol && ((DSymbol)typeToCheck).Definition is DMethod; //TODO: Alias handling, same as couple of lines above } break; case DTokens.Super: //TODO: Test this var dc = DResolver.SearchClassLikeAt(ctxt.ScopedBlock, isExpression.Location) as DClassLike; if (dc != null) { var udt = DResolver.ResolveBaseClasses(new ClassType(dc, dc, null), ctxt, true) as ClassType; if (r = udt.Base != null && ResultComparer.IsEqual(typeToCheck, udt.Base)) { var l = new List <AbstractType>(); if (udt.Base != null) { l.Add(udt.Base); } if (udt.BaseInterfaces != null && udt.BaseInterfaces.Length != 0) { l.AddRange(udt.BaseInterfaces); } res = new DTuple(isExpression, l); } } break; case DTokens.Const: case DTokens.Immutable: case DTokens.InOut: // TODO? case DTokens.Shared: if (r = typeToCheck.Modifier == isExpression.TypeSpecializationToken) { res = typeToCheck; } break; case DTokens.Return: // TODO: Test IStatement _u = null; var dm = DResolver.SearchBlockAt(ctxt.ScopedBlock, isExpression.Location, out _u) as DMethod; if (dm != null) { var retType_ = TypeDeclarationResolver.GetMethodReturnType(dm, ctxt); if (r = retType_ != null && ResultComparer.IsEqual(typeToCheck, retType_)) { res = retType_; } } break; } return(new Tuple <bool, AbstractType>(r, res)); }
/// <summary> /// a + b; a - b; etc. /// </summary> ISemantic E_MathOp(OperatorBasedExpression x, ISemantic lValue = null, ISemantic rValue = null) { if (!eval) { return(lValue ?? E(x.LeftOperand)); } var l = TryGetValue(lValue ?? E(x.LeftOperand)); if (l == null) { /* * In terms of adding opOverloading later on, * lvalue not being a PrimitiveValue shouldn't be a problem anymore - we simply had to * search the type of l for methods called opAdd etc. and call that method via ctfe. * Finally, return the value the opAdd method passed back - and everything is fine. */ /* * Also, pointers should be implemented later on. * http://dlang.org/expression.html#AddExpression */ throw new EvaluationException(x, "Left value must evaluate to a constant scalar value. Operator overloads aren't supported yet", lValue); } //TODO: Operator overloading // Note: a * b + c is theoretically treated as a * (b + c), but it's needed to evaluate it as (a * b) + c ! if (x is MulExpression || x is PowExpression) { if (x.RightOperand is OperatorBasedExpression && !(x.RightOperand is AssignExpression)) //TODO: This must be true only if it's a math expression, so not an assign expression etc. { var sx = (OperatorBasedExpression)x.RightOperand; // Now multiply/divide/mod expression 'l' with sx.LeftOperand var intermediateResult = HandleSingleMathOp(x, l, E(sx.LeftOperand), mult); // afterwards, evaluate the operation between the result just returned and the sx.RightOperand. return(E(sx, intermediateResult)); } return(HandleSingleMathOp(x, l, rValue ?? E(x.RightOperand), mult)); } var r = TryGetValue(rValue ?? E(x.RightOperand)); if (r == null) { throw new EvaluationException(x, "Right operand must evaluate to a value", lValue); } /* * TODO: Handle invalid values/value ranges. */ if (x is XorExpression) { return(HandleSingleMathOp(x, l, r, (a, b) => { EnsureIntegralType(a); EnsureIntegralType(b); return (long)a.Value ^ (long)b.Value; })); } else if (x is OrExpression) { return(HandleSingleMathOp(x, l, r, (a, b) => { EnsureIntegralType(a); EnsureIntegralType(b); return (long)a.Value | (long)b.Value; })); } else if (x is AndExpression) { return(HandleSingleMathOp(x, l, r, (a, b) => { EnsureIntegralType(a); EnsureIntegralType(b); return (long)a.Value & (long)b.Value; })); } else if (x is ShiftExpression) { return(HandleSingleMathOp(x, l, r, (a, b) => { EnsureIntegralType(a); EnsureIntegralType(b); if (b.Value < 0 || b.Value > 31) { throw new EvaluationException(b.BaseExpression, "Shift operand must be between 0 and 31", b); } switch (x.OperatorToken) { case DTokens.ShiftLeft: return (long)a.Value << (int)b.Value; // TODO: Handle the imaginary part case DTokens.ShiftRight: return (long)a.Value >> (int)b.Value; case DTokens.ShiftRightUnsigned: //TODO: Find out where's the difference between >> and >>> return (ulong)a.Value >> (int)(uint)b.Value; } throw new EvaluationException(x, "Invalid token for shift expression", l, r); })); } else if (x is AddExpression) { return(HandleSingleMathOp(x, l, r, (a, b, op) => { switch (op.OperatorToken) { case DTokens.Plus: return new PrimitiveValue(a.BaseTypeToken, a.Value + b.Value, x, a.ImaginaryPart + b.ImaginaryPart); case DTokens.Minus: return new PrimitiveValue(a.BaseTypeToken, a.Value - b.Value, x, a.ImaginaryPart - b.ImaginaryPart); } throw new EvaluationException(x, "Invalid token for add/sub expression", l, r); })); } else if (x is CatExpression) { // Notable: If one element is of the value type of the array, the element is added (either at the front or at the back) to the array var av_l = l as ArrayValue; var av_r = r as ArrayValue; if (av_l != null && av_r != null) { // Ensure that both arrays are of the same type if (!ResultComparer.IsEqual(av_l.RepresentedType, av_r.RepresentedType)) { throw new EvaluationException(x, "Both arrays must be of same type", l, r); } // Might be a string if (av_l.IsString && av_r.IsString) { return(new ArrayValue(av_l.RepresentedType as ArrayType, x, av_l.StringValue + av_r.StringValue)); } else { var elements = new ISymbolValue[av_l.Elements.Length + av_r.Elements.Length]; Array.Copy(av_l.Elements, 0, elements, 0, av_l.Elements.Length); Array.Copy(av_r.Elements, 0, elements, av_l.Elements.Length, av_r.Elements.Length); return(new ArrayValue(av_l.RepresentedType as ArrayType, elements)); } } ArrayType at = null; // Append the right value to the array if (av_l != null && (at = av_l.RepresentedType as ArrayType) != null && ResultComparer.IsImplicitlyConvertible(r.RepresentedType, at.ValueType, ctxt)) { var elements = new ISymbolValue[av_l.Elements.Length + 1]; Array.Copy(av_l.Elements, elements, av_l.Elements.Length); elements[elements.Length - 1] = r; return(new ArrayValue(at, elements)); } // Put the left value into the first position else if (av_r != null && (at = av_r.RepresentedType as ArrayType) != null && ResultComparer.IsImplicitlyConvertible(l.RepresentedType, at.ValueType, ctxt)) { var elements = new ISymbolValue[1 + av_r.Elements.Length]; elements[0] = l; Array.Copy(av_r.Elements, 0, elements, 1, av_r.Elements.Length); return(new ArrayValue(at, elements)); } throw new EvaluationException(x, "At least one operand must be an (non-associative) array. If so, the other operand must be of the array's element type.", l, r); } throw new WrongEvaluationArgException(); }
public static DNode ExamTraceSymbol(string symName, ResolutionContext ctxt, out bool mightBeLegalUnresolvableSymbol) { DSymbol ds = null; mightBeLegalUnresolvableSymbol = false; if (string.IsNullOrWhiteSpace(symName)) { return(null); } // Try to handle a probably mangled string or C function. if (symName.StartsWith("_")) { try{ ds = Demangler.DemangleAndResolve(symName, ctxt) as DSymbol; }catch {} } // Stuff like void std.stdio.File.LockingTextWriter.put!(immutable(char)[]).put(immutable(char)[]) if (ds == null && Lexer.IsIdentifierPart((int)symName[0])) { mightBeLegalUnresolvableSymbol = true; ITypeDeclaration q; var method = DParser.ParseMethodDeclarationHeader(symName, out q); q = Demangler.RemoveNestedTemplateRefsFromQualifier(q); AbstractType[] overloads = null; D_Parser.Completion.CodeCompletion.DoTimeoutableCompletionTask(null, ctxt, () => { try { overloads = AmbiguousType.TryDissolve(LooseResolution.LookupIdRawly(ctxt.ParseCache, q, ctxt.ScopedBlock.NodeRoot as DModule)).ToArray(); } catch (Exception ex) { MonoDevelop.Core.LoggingService.LogWarning("Error during trace.log symbol resolution of " + q.ToString(), ex); } }); if (overloads == null || overloads.Length == 0) { return(null); } else if (overloads.Length == 1) { ds = overloads[0] as DSymbol; } else { method.Type = Demangler.RemoveNestedTemplateRefsFromQualifier(method.Type); var methodType = TypeDeclarationResolver.GetMethodReturnType(method, ctxt); var methodParameters = new List <AbstractType>(); D_Parser.Completion.CodeCompletion.DoTimeoutableCompletionTask(null, ctxt, () => { if (method.Parameters != null && method.Parameters.Count != 0) { foreach (var parm in method.Parameters) { methodParameters.Add(TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(parm.Type), ctxt)); } } }); foreach (var o in overloads) { ds = o as DSymbol; if (ds == null || !(ds.Definition is DMethod)) { continue; } var dm = ds.Definition as DMethod; // Compare return types if (dm.Type != null) { if (methodType == null || ds.Base == null || !ResultComparer.IsEqual(methodType, ds.Base)) { continue; } } else if (dm.Type == null && methodType != null) { return(null); } // Compare parameters if (methodParameters.Count != dm.Parameters.Count) { continue; } for (int i = 0; i < methodParameters.Count; i++) { if (!ResultComparer.IsImplicitlyConvertible(methodParameters[i], TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(dm.Parameters[i].Type), ctxt))) { continue; } } } } } return(ds != null ? ds.Definition : null); }