private static bool DeduceParams(IEnumerable <ISemantic> givenTemplateArguments, bool isMethodCall, ResolutionContext ctxt, DSymbol overload, DNode tplNode, DeducedTypeDictionary deducedTypes) { bool isLegitOverload = true; var paramEnum = tplNode.TemplateParameters.GetEnumerator(); var args = givenTemplateArguments ?? new List <ISemantic> (); var argEnum = args.GetEnumerator(); foreach (var expectedParam in tplNode.TemplateParameters) { if (!DeduceParam(ctxt, overload, deducedTypes, argEnum, expectedParam)) { isLegitOverload = false; break; // Don't check further params if mismatch has been found } } if (!isMethodCall && argEnum.MoveNext()) { // There are too many arguments passed - discard this overload isLegitOverload = false; } return(isLegitOverload); }
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); }
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; if (overload == null) { if (!hasTemplateArgsPassed) { filteredOverloads.Add(o); } continue; } var tplNode = overload.Definition; // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params if (tplNode == null) { filteredOverloads.Add(overload); 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(overload); } continue; } var deducedTypes = new DeducedTypeDictionary(tplNode); if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes)) { overload.DeducedTypes = deducedTypes.ToReadonly(); // Assign calculated types to final result filteredOverloads.Add(overload); } else { overload.DeducedTypes = null; } } return(filteredOverloads); }
static bool CheckAndDeduceTypeAgainstTplParameter(TemplateParameter handledParameter, ISemantic argumentToCheck, DeducedTypeDictionary deducedTypes, ResolutionContext ctxt) { return(new Templates.TemplateParameterDeduction(deducedTypes, ctxt).Handle(handledParameter, argumentToCheck)); }
static bool CheckAndDeduceTypeTuple(TemplateTupleParameter tupleParameter, IEnumerable <ISemantic> typeChain, DeducedTypeDictionary deducedTypes, ResolutionContext ctxt) { return(new Templates.TemplateParameterDeduction(deducedTypes, ctxt).Handle(tupleParameter, typeChain)); }
public static bool AllParamatersSatisfied(DeducedTypeDictionary deductions) { foreach (var kv in deductions) if (kv.Value == null || kv.Value==null) return false; return true; }
private bool evalIsExpression_WithAliases(IsExpression isExpression, AbstractType typeToCheck) { /* * Note: It's needed to let the abstract ast scanner also scan through IsExpressions etc. * in order to find aliases and/or specified template parameters! */ var expectedTemplateParams = new TemplateParameter[isExpression.TemplateParameterList.Length + 1]; expectedTemplateParams [0] = isExpression.ArtificialFirstSpecParam; if (expectedTemplateParams.Length > 1) { isExpression.TemplateParameterList.CopyTo(expectedTemplateParams, 1); } var tpl_params = new DeducedTypeDictionary(expectedTemplateParams); var tpd = new TemplateParameterDeduction(tpl_params, ctxt); bool retTrue = false; if (isExpression.EqualityTest) // 6. { // a) if (isExpression.TypeSpecialization != null) { tpd.EnforceTypeEqualityWhenDeducing = true; retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck); tpd.EnforceTypeEqualityWhenDeducing = false; } else // b) { var r = evalIsExpression_EvalSpecToken(isExpression, typeToCheck, true); retTrue = r.Item1; tpl_params[isExpression.TypeAliasIdentifierHash] = new TemplateParameterSymbol(null, r.Item2); } } else // 5. { retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck); } if (retTrue && isExpression.TemplateParameterList != null) { foreach (var p in isExpression.TemplateParameterList) { if (!tpd.Handle(p, tpl_params[p.NameHash] != null ? tpl_params[p.NameHash].Base : null)) { return(false); } } } //TODO: Put all tpl_params results into the resolver context or make a new scope or something! return(retTrue); }
public static bool AllParamatersSatisfied(DeducedTypeDictionary deductions) { foreach (var kv in deductions) { if (kv.Value == null || kv.Value == null) { return(false); } } return(true); }
private bool evalIsExpression_WithAliases(IsExpression isExpression, AbstractType typeToCheck) { /* * Note: It's needed to let the abstract ast scanner also scan through IsExpressions etc. * in order to find aliases and/or specified template parameters! */ var expectedTemplateParams = new TemplateParameter[isExpression.TemplateParameterList == null ? 1 : (isExpression.TemplateParameterList.Length + 1)]; expectedTemplateParams [0] = isExpression.ArtificialFirstSpecParam; if(expectedTemplateParams.Length > 1) isExpression.TemplateParameterList.CopyTo (expectedTemplateParams, 1); var tpl_params = new DeducedTypeDictionary(expectedTemplateParams); var tpd = new TemplateParameterDeduction(tpl_params, ctxt); bool retTrue = false; if (isExpression.EqualityTest) // 6. { // a) if (isExpression.TypeSpecialization != null) { tpd.EnforceTypeEqualityWhenDeducing = true; retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck); tpd.EnforceTypeEqualityWhenDeducing = false; } else // b) { var r = evalIsExpression_EvalSpecToken(isExpression, typeToCheck, true); retTrue = r.Item1; tpl_params[isExpression.ArtificialFirstSpecParam] = new TemplateParameterSymbol(isExpression.ArtificialFirstSpecParam, r.Item2); } } else // 5. retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck); if (retTrue && isExpression.TemplateParameterList != null) foreach (var p in isExpression.TemplateParameterList) if (!tpd.Handle(p, tpl_params[p] != null ? tpl_params[p].Base : null)) return false; if (retTrue) { foreach (var kv in tpl_params) ctxt.CurrentContext.DeducedTemplateParameters[kv.Key] = kv.Value; } return retTrue; }
public string GenTooltipSignature(DNode dn, bool templateParamCompletion = false, int currentMethodParam = -1, ITypeDeclaration baseType=null, DeducedTypeDictionary deducedType = null) { var sb = new StringBuilder(); if (dn is DMethod) S (dn as DMethod, sb, templateParamCompletion, currentMethodParam, baseType, deducedType); else if (dn is DModule) { sb.Append ("<i>(Module)</i> ").Append ((dn as DModule).ModuleName); } else if (dn is DClassLike) S (dn as DClassLike, sb, deducedType); else if(dn != null) AttributesTypeAndName (dn, sb, baseType, -1, deducedType); return sb.ToString (); }
void AttributesTypeAndName(DNode dn, StringBuilder sb, ITypeDeclaration baseType = null, int highlightTemplateParam = -1, DeducedTypeDictionary deducedTypes = null) { AppendAttributes(dn, sb, baseType == null); if (dn.Type != null || baseType != null) { sb.Append(DCodeToMarkup((baseType ?? dn.Type).ToString(true))).Append(' '); } // Maybe highlight variables/method names? sb.Append(dn.Name); AppendTemplateParams(dn, sb, highlightTemplateParam, deducedTypes); }
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); }
public bool Handle(TemplateParameter parameter, ISemantic argumentToAnalyze) { // Packages aren't allowed at all if (argumentToAnalyze is PackageSymbol) return false; // Module symbols can be used as alias only if (argumentToAnalyze is ModuleSymbol && !(parameter is TemplateAliasParameter)) return false; //TODO: Handle __FILE__ and __LINE__ correctly - so don't evaluate them at the template declaration but at the point of instantiation /* * Introduce previously deduced parameters into current resolution context * to allow value parameter to be of e.g. type T whereas T is already set somewhere before */ DeducedTypeDictionary _prefLocalsBackup = null; if (ctxt != null && ctxt.CurrentContext != null) { _prefLocalsBackup = ctxt.CurrentContext.DeducedTemplateParameters; var d = new DeducedTypeDictionary(); foreach (var kv in TargetDictionary) if (kv.Value != null) d[kv.Key] = kv.Value; ctxt.CurrentContext.DeducedTemplateParameters = d; } bool res = false; if (parameter is TemplateAliasParameter) res = Handle((TemplateAliasParameter)parameter, argumentToAnalyze); else if (parameter is TemplateThisParameter) res = Handle((TemplateThisParameter)parameter, argumentToAnalyze); else if (parameter is TemplateTypeParameter) res = Handle((TemplateTypeParameter)parameter, argumentToAnalyze); else if (parameter is TemplateValueParameter) res = Handle((TemplateValueParameter)parameter, argumentToAnalyze); else if (parameter is TemplateTupleParameter) res = Handle((TemplateTupleParameter)parameter, new[] { argumentToAnalyze }); if (ctxt != null && ctxt.CurrentContext != null) ctxt.CurrentContext.DeducedTemplateParameters = _prefLocalsBackup; return res; }
private bool evalIsExpression_WithAliases(IsExpression isExpression, AbstractType typeToCheck) { /* * Note: It's needed to let the abstract ast scanner also scan through IsExpressions etc. * in order to find aliases and/or specified template parameters! */ var expectedTemplateParams = new TemplateParameter[isExpression.TemplateParameterList.Length + 1]; expectedTemplateParams [0] = isExpression.ArtificialFirstSpecParam; if(expectedTemplateParams.Length > 1) isExpression.TemplateParameterList.CopyTo (expectedTemplateParams, 1); var tpl_params = new DeducedTypeDictionary(expectedTemplateParams); var tpd = new TemplateParameterDeduction(tpl_params, ctxt); bool retTrue = false; if (isExpression.EqualityTest) // 6. { // a) if (isExpression.TypeSpecialization != null) { tpd.EnforceTypeEqualityWhenDeducing = true; retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck); tpd.EnforceTypeEqualityWhenDeducing = false; } else // b) { var r = evalIsExpression_EvalSpecToken(isExpression, typeToCheck, true); retTrue = r.Item1; tpl_params[isExpression.TypeAliasIdentifierHash] = new TemplateParameterSymbol(null, r.Item2); } } else // 5. retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck); if (retTrue && isExpression.TemplateParameterList != null) foreach (var p in isExpression.TemplateParameterList) if (!tpd.Handle(p, tpl_params[p.NameHash] != null ? tpl_params[p.NameHash].Base : null)) return false; //TODO: Put all tpl_params results into the resolver context or make a new scope or something! return retTrue; }
void S(DClassLike dc, StringBuilder sb, DeducedTypeDictionary deducedTypes = null) { AppendAttributes(dc, sb); sb.Append(DCodeToMarkup(DTokens.GetTokenString(dc.ClassType))).Append(' '); sb.Append(DCodeToMarkup(dc.Name)); AppendTemplateParams(dc, sb, -1, deducedTypes); if (dc.BaseClasses != null && dc.BaseClasses.Count != 0) { sb.AppendLine(" : "); sb.Append(" "); foreach (var bc in dc.BaseClasses) { sb.Append(' ').Append(DCodeToMarkup(bc.ToString())).Append(','); } RemoveLastChar(sb, ','); } AppendConstraint(dc, sb); }
ISemantic E(PostfixExpression_MethodCall call, bool returnBaseTypeOnly=true) { // Deduce template parameters later on AbstractType[] baseExpression; ISymbolValue baseValue; TemplateInstanceExpression tix; GetRawCallOverloads(call, out baseExpression, out baseValue, out tix); var methodOverloads = new List<AbstractType>(); #region Search possible methods, opCalls or delegates that could be called bool requireStaticItems = true; //TODO: What if there's an opCall and a foreign method at the same time? - and then this variable would be bullshit IEnumerable<AbstractType> scanResults = DResolver.StripAliasSymbols(baseExpression); var nextResults = new List<AbstractType>(); while (scanResults != null) { foreach (var b in scanResults) { if (b is MemberSymbol) { var mr = (MemberSymbol)b; if (mr.Definition is DMethod) { methodOverloads.Add(mr); continue; } else if (mr.Definition is DVariable) { // If we've got a variable here, get its base type/value reference if (eval) { var dgVal = ValueProvider[(DVariable)mr.Definition] as DelegateValue; if (dgVal != null) { nextResults.Add(dgVal.Definition); continue; } else{ EvalError(call, "Variable must be a delegate, not anything else", mr); return null; } } else { var bt = DResolver.StripAliasSymbol(mr.Base ?? TypeDeclarationResolver.ResolveSingle(mr.Definition.Type, ctxt)); // Must be of type delegate if (bt is DelegateType) { //TODO: Ensure that there's no further overload - inform the user elsewise if (returnBaseTypeOnly) return bt; else return new MemberSymbol(mr.Definition, bt, mr.DeclarationOrExpressionBase); } else { /* * If mr.Node is not a method, so e.g. if it's a variable * pointing to a delegate * * class Foo * { * string opCall() { return "asdf"; } * } * * Foo f=new Foo(); * f(); -- calls opCall, opCall is not static */ nextResults.Add(bt); requireStaticItems = false; } //TODO: Can other types work as function/are callable? } } } else if (b is DelegateType) { var dg = (DelegateType)b; /* * int a = delegate(x) { return x*2; } (12); // a is 24 after execution * auto dg=delegate(x) {return x*3;}; * int b = dg(4); */ if (dg.IsFunctionLiteral) methodOverloads.Add(dg); else { // If it's just wanted to pass back the delegate's return type, skip the remaining parts of this method. if (eval) { EvalError(call, "TODO", dg); return null; } //TODO //if(returnBaseTypeOnly) //TODO: Check for multiple definitions. Also, make a parameter-argument check to inform the user about wrong arguments. return dg; } } else if (b is ClassType || b is StructType) { var tit = (TemplateIntermediateType)b; /* * auto a = MyStruct(); -- opCall-Overloads can be used */ var classDef = tit.Definition; if (classDef == null) continue; foreach (var i in GetOpCalls(tit, requireStaticItems)) methodOverloads.Add(TypeDeclarationResolver.HandleNodeMatch(i, ctxt, b, call) as MemberSymbol); /* * Every struct can contain a default ctor: * * struct S { int a; bool b; } * * auto s = S(1,true); -- ok * auto s2= new S(2,false); -- error, no constructor found! */ if (b is StructType && methodOverloads.Count == 0) { //TODO: Deduce parameters return b; } } /* * If the overload is a template, it quite exclusively means that we'll handle a method that is the only * child inside a template + that is named as the template. */ else if (b is TemplateType) methodOverloads.Add(b); } scanResults = nextResults.Count == 0 ? null : nextResults.ToArray(); nextResults.Clear(); } #endregion if (methodOverloads.Count == 0) return null; // Get all arguments' types var callArguments = new List<ISemantic>(); bool hasNonFinalArgs = false; if (call.Arguments != null) foreach (var arg in call.Arguments) callArguments.Add(E(arg)); #region If explicit template type args were given, try to associate them with each overload if (tix != null) { var args = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt, out hasNonFinalArgs); var deducedOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(methodOverloads, args, true, ctxt, hasNonFinalArgs); methodOverloads.Clear(); if(deducedOverloads != null) methodOverloads.AddRange(deducedOverloads); } #endregion #region Filter by parameter-argument comparison var argTypeFilteredOverloads = new List<AbstractType>(); bool hasHandledUfcsResultBefore = false; foreach (var ov in methodOverloads) { if (ov is MemberSymbol) { var ms = ov as MemberSymbol; var dm = ms.Definition as DMethod; if (dm != null) { // In the case of an ufcs, insert the first argument into the CallArguments list if (ms.IsUFCSResult && !hasHandledUfcsResultBefore) { callArguments.Insert(0, eval ? baseValue as ISemantic : ((MemberSymbol)baseExpression[0]).FirstArgument); hasHandledUfcsResultBefore = true; } else if (!ms.IsUFCSResult && 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; } var deducedTypeDict = new DeducedTypeDictionary(ms); var templateParamDeduction = new TemplateParameterDeduction(deducedTypeDict, ctxt); if(dm.Parameters.Count == 0 && callArguments.Count > 0) continue; int currentArg = 0; bool add = true; if (dm.Parameters.Count > 0 || callArguments.Count > 0) for (int i=0; i< dm.Parameters.Count; i++) { var paramType = dm.Parameters[i].Type; // 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(ref add, callArguments, dm, deducedTypeDict, i, ref currentArg)) continue; else if (currentArg < callArguments.Count) { if (!templateParamDeduction.HandleDecl(null, paramType, callArguments[currentArg++])) { add = false; break; } } else { // If there are more parameters than arguments given, check if the param has default values if (!(dm.Parameters[i] is DVariable) || (dm.Parameters[i] as DVariable).Initializer == null) { add = false; break; } // Assume that all further method parameters do have default values - and don't check further parameters break; } } // If type params were unassigned, try to take the defaults if (add && dm.TemplateParameters != null) { foreach (var tpar in dm.TemplateParameters) { if (deducedTypeDict[tpar.NameHash] == null) { add = templateParamDeduction.Handle(tpar, null); if (!add) { if (hasNonFinalArgs) { deducedTypeDict[tpar] = new TemplateParameterSymbol(tpar, null); add = true; } else break; } } } } if (add && (deducedTypeDict.AllParamatersSatisfied || hasNonFinalArgs)) { ms.DeducedTypes = deducedTypeDict.ToReadonly(); var pop = ctxt.ScopedBlock != dm; if(pop) ctxt.PushNewScope(dm); ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); var bt=ms.Base ?? TypeDeclarationResolver.GetMethodReturnType(dm, ctxt); if(pop) ctxt.Pop(); else ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms); if(eval || !returnBaseTypeOnly) argTypeFilteredOverloads.Add(ms.Base == null ? new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) : ms); else argTypeFilteredOverloads.Add(bt); } } } else if(ov is DelegateType) { var dg = (DelegateType)ov; var bt = TypeDeclarationResolver.GetMethodReturnType(dg, ctxt); //TODO: Param-Arg check if (!eval || returnBaseTypeOnly) argTypeFilteredOverloads.Add(bt); else argTypeFilteredOverloads.Add(new DelegateType(bt, dg.DeclarationOrExpressionBase as FunctionLiteral, dg.Parameters)); } } #endregion if (eval) { // Convert ISemantic[] to ISymbolValue[] var args = new List<ISymbolValue>(callArguments.Count); foreach (var a in callArguments) args.Add(a as ISymbolValue); // Execute/Evaluate the variable contents etc. return TryDoCTFEOrGetValueRefs(argTypeFilteredOverloads.ToArray(), call.PostfixForeExpression, true, args.ToArray()); } else { // Check if one overload remains and return that one. ctxt.CheckForSingleResult(argTypeFilteredOverloads.ToArray(), call); return argTypeFilteredOverloads.Count != 0 ? argTypeFilteredOverloads[0] : null; } }
static AbstractType[] TryGetImplicitProperty(TemplateType template, ResolutionContext ctxt) { // 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; } return matchingChild; }
ISemantic E(PostfixExpression_MethodCall call, bool returnBaseTypeOnly = true) { // Deduce template parameters later on AbstractType[] baseExpression; ISymbolValue baseValue; TemplateInstanceExpression tix; GetRawCallOverloads(call, out baseExpression, out baseValue, out tix); var methodOverloads = new List <AbstractType>(); #region Search possible methods, opCalls or delegates that could be called bool requireStaticItems = true; //TODO: What if there's an opCall and a foreign method at the same time? - and then this variable would be bullshit IEnumerable <AbstractType> scanResults = DResolver.StripAliasSymbols(baseExpression); var nextResults = new List <AbstractType>(); while (scanResults != null) { foreach (var b in scanResults) { if (b is MemberSymbol) { var mr = (MemberSymbol)b; if (mr.Definition is DMethod) { methodOverloads.Add(mr); continue; } else if (mr.Definition is DVariable) { // If we've got a variable here, get its base type/value reference if (eval) { var dgVal = ValueProvider[(DVariable)mr.Definition] as DelegateValue; if (dgVal != null) { nextResults.Add(dgVal.Definition); continue; } else { EvalError(call, "Variable must be a delegate, not anything else", mr); return(null); } } else { var bt = DResolver.StripAliasSymbol(mr.Base ?? TypeDeclarationResolver.ResolveSingle(mr.Definition.Type, ctxt)); // Must be of type delegate if (bt is DelegateType) { //TODO: Ensure that there's no further overload - inform the user elsewise if (returnBaseTypeOnly) { return(bt); } else { return(new MemberSymbol(mr.Definition, bt, mr.DeclarationOrExpressionBase)); } } else { /* * If mr.Node is not a method, so e.g. if it's a variable * pointing to a delegate * * class Foo * { * string opCall() { return "asdf"; } * } * * Foo f=new Foo(); * f(); -- calls opCall, opCall is not static */ nextResults.Add(bt); requireStaticItems = false; } //TODO: Can other types work as function/are callable? } } } else if (b is DelegateType) { var dg = (DelegateType)b; /* * int a = delegate(x) { return x*2; } (12); // a is 24 after execution * auto dg=delegate(x) {return x*3;}; * int b = dg(4); */ if (dg.IsFunctionLiteral) { methodOverloads.Add(dg); } else { // If it's just wanted to pass back the delegate's return type, skip the remaining parts of this method. if (eval) { EvalError(call, "TODO", dg); return(null); } //TODO //if(returnBaseTypeOnly) //TODO: Check for multiple definitions. Also, make a parameter-argument check to inform the user about wrong arguments. return(dg); } } else if (b is ClassType || b is StructType) { var tit = (TemplateIntermediateType)b; /* * auto a = MyStruct(); -- opCall-Overloads can be used */ var classDef = tit.Definition; if (classDef == null) { continue; } foreach (var i in GetOpCalls(tit, requireStaticItems)) { methodOverloads.Add(TypeDeclarationResolver.HandleNodeMatch(i, ctxt, b, call) as MemberSymbol); } /* * Every struct can contain a default ctor: * * struct S { int a; bool b; } * * auto s = S(1,true); -- ok * auto s2= new S(2,false); -- error, no constructor found! */ if (b is StructType && methodOverloads.Count == 0) { //TODO: Deduce parameters return(b); } } /* * If the overload is a template, it quite exclusively means that we'll handle a method that is the only * child inside a template + that is named as the template. */ else if (b is TemplateType) { methodOverloads.Add(b); } } scanResults = nextResults.Count == 0 ? null : nextResults.ToArray(); nextResults.Clear(); } #endregion if (methodOverloads.Count == 0) { return(null); } // Get all arguments' types var callArguments = new List <ISemantic>(); bool hasNonFinalArgs = false; if (call.Arguments != null) { foreach (var arg in call.Arguments) { callArguments.Add(E(arg)); } } #region If explicit template type args were given, try to associate them with each overload if (tix != null) { var args = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt, out hasNonFinalArgs); var deducedOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(methodOverloads, args, true, ctxt, hasNonFinalArgs); methodOverloads.Clear(); if (deducedOverloads != null) { methodOverloads.AddRange(deducedOverloads); } } #endregion #region Filter by parameter-argument comparison var argTypeFilteredOverloads = new List <AbstractType>(); bool hasHandledUfcsResultBefore = false; foreach (var ov in methodOverloads) { if (ov is MemberSymbol) { var ms = ov as MemberSymbol; var dm = ms.Definition as DMethod; if (dm != null) { // In the case of an ufcs, insert the first argument into the CallArguments list if (ms.IsUFCSResult && !hasHandledUfcsResultBefore) { callArguments.Insert(0, eval ? baseValue as ISemantic : ((MemberSymbol)baseExpression[0]).FirstArgument); hasHandledUfcsResultBefore = true; } else if (!ms.IsUFCSResult && 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; } var deducedTypeDict = new DeducedTypeDictionary(ms); if (dm.TemplateParameters != null) { foreach (var tpar in dm.TemplateParameters) { if (!deducedTypeDict.ContainsKey(tpar.NameHash)) { deducedTypeDict[tpar.NameHash] = null; } } } var templateParamDeduction = new TemplateParameterDeduction(deducedTypeDict, ctxt); int currentArg = 0; bool add = true; if (callArguments.Count > 0 || dm.Parameters.Count > 0) { for (int i = 0; i < dm.Parameters.Count; i++) { var paramType = dm.Parameters[i].Type; // 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(ref add, callArguments, dm, deducedTypeDict, i, ref currentArg)) { continue; } else if (currentArg < callArguments.Count) { if (!templateParamDeduction.HandleDecl(null, paramType, callArguments[currentArg++])) { add = false; break; } } else { // If there are more parameters than arguments given, check if the param has default values if (!(dm.Parameters[i] is DVariable) || (dm.Parameters[i] as DVariable).Initializer == null) { add = false; break; } // Assume that all further method parameters do have default values - and don't check further parameters break; } } } // If type params were unassigned, try to take the defaults if (add && dm.TemplateParameters != null) { foreach (var tpar in dm.TemplateParameters) { if (deducedTypeDict[tpar.NameHash] == null) { add = templateParamDeduction.Handle(tpar, null); if (!add) { if (hasNonFinalArgs) { deducedTypeDict[tpar.NameHash] = new TemplateParameterSymbol(tpar, null); add = true; } else { break; } } } } } if (add && (deducedTypeDict.AllParamatersSatisfied || hasNonFinalArgs)) { ms.DeducedTypes = deducedTypeDict.ToReadonly(); ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); var bt = ms.Base ?? TypeDeclarationResolver.GetMethodReturnType(dm, ctxt); ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms); if (eval || !returnBaseTypeOnly) { argTypeFilteredOverloads.Add(ms.Base == null ? new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) : ms); } else { argTypeFilteredOverloads.Add(bt); } } } } else if (ov is DelegateType) { var dg = (DelegateType)ov; var bt = TypeDeclarationResolver.GetMethodReturnType(dg, ctxt); //TODO: Param-Arg check if (!eval || returnBaseTypeOnly) { argTypeFilteredOverloads.Add(bt); } else { argTypeFilteredOverloads.Add(new DelegateType(bt, dg.DeclarationOrExpressionBase as FunctionLiteral, dg.Parameters)); } } } #endregion if (eval) { // Convert ISemantic[] to ISymbolValue[] var args = new List <ISymbolValue>(callArguments.Count); foreach (var a in callArguments) { args.Add(a as ISymbolValue); } // Execute/Evaluate the variable contents etc. return(TryDoCTFEOrGetValueRefs(argTypeFilteredOverloads.ToArray(), call.PostfixForeExpression, true, args.ToArray())); } else { // Check if one overload remains and return that one. ctxt.CheckForSingleResult(argTypeFilteredOverloads.ToArray(), call); return(argTypeFilteredOverloads.Count != 0 ? argTypeFilteredOverloads[0] : null); } }
/// <summary> /// Checks results for implicit type convertability /// </summary> public static bool IsImplicitlyConvertible(ISemantic resultToCheck, AbstractType targetType, ResolverContextStack ctxt = null) { var resToCheck = AbstractType.Get(resultToCheck); // Initially remove aliases from results var _r = DResolver.StripMemberSymbols(resToCheck); if (_r == null) { return(IsEqual(resToCheck, targetType)); } resToCheck = _r; targetType = DResolver.StripAliasSymbol(targetType); if (targetType is DSymbol) { var tpn = ((DSymbol)targetType).Definition as TemplateParameterNode; if (tpn != null) { var par = tpn.Parent as DNode; if (par != null && par.TemplateParameters != null) { var dedParam = new DeducedTypeDictionary { ParameterOwner = par }; foreach (var tp in par.TemplateParameters) { dedParam[tp.Name] = null; } return(new TemplateParameterDeduction(dedParam, ctxt).Handle(tpn.TemplateParameter, resToCheck)); } } } _r = DResolver.StripMemberSymbols(targetType); if (_r == null) { return(false); } targetType = _r; if (resToCheck is PrimitiveType && targetType is PrimitiveType) { var sr1 = (PrimitiveType)resToCheck; var sr2 = (PrimitiveType)targetType; if (sr1.TypeToken == sr2.TypeToken && sr1.Modifier == sr2.Modifier) { return(true); } switch (sr2.TypeToken) { case DTokens.Int: return(sr1.TypeToken == DTokens.Uint); case DTokens.Uint: return(sr1.TypeToken == DTokens.Int); //TODO: Further types that can be converted into each other implicitly } } else if (resToCheck is UserDefinedType && targetType is UserDefinedType) { return(IsImplicitlyConvertible((UserDefinedType)resToCheck, (UserDefinedType)targetType)); } else if (resToCheck is DelegateType && targetType is DelegateType) { //TODO } else if (resToCheck is ArrayType && targetType is ArrayType) { var ar1 = (ArrayType)resToCheck; var ar2 = (ArrayType)targetType; // Key as well as value types must be matching! var ar1_n = ar1.KeyType == null; var ar2_n = ar2.KeyType == null; if (ar1_n != ar2_n) { return(false); } if (ar1_n || IsImplicitlyConvertible(ar1.KeyType, ar2.KeyType, ctxt)) { return(IsImplicitlyConvertible(ar1.Base, ar2.Base, ctxt)); } } else if (resToCheck is TypeTuple && targetType is TypeTuple) { return(true); } else if (resToCheck is ExpressionTuple && targetType is ExpressionTuple) { return(true); } /*else if (resultToCheck is ExpressionValueResult && targetType is ExpressionValue) * { * return ((ExpressionValueResult)resultToCheck).Value.Equals(((ExpressionValueResult)targetType).Value); * }*/ // http://dlang.org/type.html //TODO: Pointer to non-pointer / vice-versa checkability? -- Can it really be done implicitly? return(false); }
/*void S(DelegateType dt, StringBuilder sb, bool templArgs = false, int curArg = -1) * { * if (dt.ReturnType != null) * sb.Append(DCodeToMarkup(dt.ReturnType.ToCode(true))).Append(' '); * * // Parameters * sb.Append('('); * * if (dt.Parameters != null) * { * for (int i = 0; i < dt.Parameters.Length; i++) * { * sb.AppendLine(); * sb.Append(" "); * * var parm = dt.Parameters[i]; * * var indexBackup = sb.Length; * * //TODO: Show deduced parameters * AttributesTypeAndName(parm, sb); * * if (!templArgs && curArg == i) * { * //TODO: Optimize * var contentToUnderline = sb.ToString(indexBackup, sb.Length - indexBackup); * sb.Remove(indexBackup, contentToUnderline.Length); * AppendFormat(contentToUnderline, sb, FormatFlags.Underline); * } * * if (parm is DVariable && (parm as DVariable).Initializer != null) * sb.Append(" = ").Append((parm as DVariable).Initializer.ToString()); * * sb.Append(','); * } * * RemoveLastChar(sb, ','); * sb.AppendLine(); * } * * sb.Append(')'); * }*/ void S(DMethod dm, StringBuilder sb, bool templArgs = false, int curArg = -1, ITypeDeclaration baseType = null, DeducedTypeDictionary deducedTypes = null) { AttributesTypeAndName(dm, sb, baseType, templArgs ? curArg : -1, deducedTypes); // Parameters sb.Append('('); if (dm.Parameters.Count != 0) { for (int i = 0; i < dm.Parameters.Count; i++) { if ((SignatureFlags & TooltipSignatureFlags.NoLineBreakedMethodParameters) == 0) { sb.AppendLine().Append(" "); } var parm = dm.Parameters[i] as DNode; var indexBackup = sb.Length; var addSqareBrackets = (this.SignatureFlags & TooltipSignatureFlags.NoEnsquaredDefaultParams) == 0; var isOpt = (this.SignatureFlags & TooltipSignatureFlags.NoDefaultParams) == 0 && parm is DVariable && (parm as DVariable).Initializer != null; if (isOpt && addSqareBrackets) { sb.Append('['); } //TODO: Show deduced parameters AttributesTypeAndName(parm, sb); if (!templArgs && curArg == i) { //TODO: Optimize var contentToUnderline = sb.ToString(indexBackup, sb.Length - indexBackup); sb.Remove(indexBackup, contentToUnderline.Length); AppendFormat(contentToUnderline, sb, FormatFlags.Underline); } if (isOpt) { sb.Append(" = ").Append(DCodeToMarkup((parm as DVariable).Initializer.ToString())); if (addSqareBrackets) { sb.Append(']'); } } sb.Append(','); } RemoveLastChar(sb, ','); if ((SignatureFlags & TooltipSignatureFlags.NoLineBreakedMethodParameters) == 0) { sb.AppendLine(); } } sb.Append(')'); AppendConstraint(dm, sb); }
private static bool DeduceParam(ResolutionContext ctxt, DSymbol overload, DeducedTypeDictionary deducedTypes, IEnumerator<ISemantic> argEnum, TemplateParameter expectedParam) { if (expectedParam is TemplateThisParameter && overload.Base != null) { var ttp = (TemplateThisParameter)expectedParam; // Get the type of the type of 'this' - so of the result that is the overload's base var t = DResolver.StripMemberSymbols(overload.Base); if (t == null || t.DeclarationOrExpressionBase == null) return false; //TODO: Still not sure if it's ok to pass a type result to it // - looking at things like typeof(T) that shall return e.g. const(A) instead of A only. if (!CheckAndDeduceTypeAgainstTplParameter(ttp, t, deducedTypes, ctxt)) return false; return true; } // Used when no argument but default arg given bool useDefaultType = false; if (argEnum.MoveNext() || (useDefaultType = HasDefaultType(expectedParam))) { // On tuples, take all following arguments and pass them to the check function if (expectedParam is TemplateTupleParameter) { var tupleItems = new List<ISemantic>(); // A tuple must at least contain one item! tupleItems.Add(argEnum.Current); while (argEnum.MoveNext()) tupleItems.Add(argEnum.Current); if (!CheckAndDeduceTypeTuple((TemplateTupleParameter)expectedParam, tupleItems, deducedTypes, ctxt)) return false; } else if (argEnum.Current != null) { if (!CheckAndDeduceTypeAgainstTplParameter(expectedParam, argEnum.Current, deducedTypes, ctxt)) return false; } else if (useDefaultType && CheckAndDeduceTypeAgainstTplParameter(expectedParam, null, deducedTypes, ctxt)) { // It's legit - just do nothing } else return false; } else if(expectedParam is TemplateTupleParameter) { if(!CheckAndDeduceTypeTuple(expectedParam as TemplateTupleParameter, null, deducedTypes, ctxt)) return false; } // There might be too few args - but that doesn't mean that it's not correct - it's only required that all parameters got satisfied with a type else if (!deducedTypes.AllParamatersSatisfied) return false; return true; }
static void HandleDMethodOverload(ResolutionContext ctxt, bool eval, ISymbolValue baseValue, List <ISemantic> callArguments, bool returnBaseTypeOnly, List <AbstractType> argTypeFilteredOverloads, ref bool hasHandledUfcsResultBefore, MemberSymbol ms, ref AbstractType untemplatedMethod) { 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 back = ctxt.ScopedBlock; using (ctxt.Push(ms)) { if (ctxt.ScopedBlock != back) { ctxt.CurrentContext.DeducedTemplateParameters = deducedTypeDict; } bool add = true; int currentArg = 0; if (dm.Parameters.Count > 0 || callArguments.Count > 0) { bool hadDTuples = false; for (int i = 0; i < dm.Parameters.Count; i++) { var paramType = dm.Parameters[i].Type; // 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 && (hadDTuples |= 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; } } // Too few args if (!hadDTuples && currentArg < callArguments.Count) { add = false; } } if (!add) { 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)) { return; } } } if (deducedTypeDict.AllParamatersSatisfied) { ms.DeducedTypes = deducedTypeDict.ToReadonly(); var bt = TypeDeclarationResolver.GetMethodReturnType(dm, ctxt) ?? ms.Base; if (eval || !returnBaseTypeOnly) { bt = new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) { Tag = ms.Tag } } ; if (dm.TemplateParameters == null || dm.TemplateParameters.Length == 0) { untemplatedMethod = bt; //ISSUE: Have another state that indicates an ambiguous non-templated method matching. } argTypeFilteredOverloads.Add(bt); } } }
private static List <AbstractType> DeduceOverloads( IEnumerable <AbstractType> rawOverloadList, IEnumerable <ISemantic> givenTemplateArguments, bool isMethodCall, ResolverContextStack ctxt) { bool hasTemplateArgsPassed = givenTemplateArguments != null; if (hasTemplateArgsPassed) { var enumm = givenTemplateArguments.GetEnumerator(); hasTemplateArgsPassed = enumm.MoveNext(); enumm.Dispose(); } var filteredOverloads = new List <AbstractType>(); if (rawOverloadList == null) { return(filteredOverloads); } foreach (var o in DResolver.StripAliasSymbols(rawOverloadList)) { if (!(o is DSymbol)) { if (!hasTemplateArgsPassed) { filteredOverloads.Add(o); } continue; } var overload = (DSymbol)o; var tplNode = overload.Definition; // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params if (tplNode == null) { filteredOverloads.Add(overload); 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(overload); } continue; } var deducedTypes = new DeducedTypeDictionary { ParameterOwner = tplNode }; foreach (var param in tplNode.TemplateParameters) { deducedTypes[param.Name] = null; // Init all params to null to let deduction functions know what params there are } if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes)) { overload.DeducedTypes = deducedTypes.ToReadonly(); // Assign calculated types to final result filteredOverloads.Add(overload); } else { overload.DeducedTypes = null; } } return(filteredOverloads); }
static bool CheckAndDeduceTypeTuple(TemplateTupleParameter tupleParameter, IEnumerable<ISemantic> typeChain, DeducedTypeDictionary deducedTypes, ResolutionContext ctxt) { return new Templates.TemplateParameterDeduction(deducedTypes,ctxt).Handle(tupleParameter,typeChain); }
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); }
/// <summary> /// Checks results for implicit type convertability /// </summary> public static bool IsImplicitlyConvertible(ISemantic resultToCheck, AbstractType targetType, ResolverContextStack ctxt=null) { var resToCheck = AbstractType.Get(resultToCheck); // Initially remove aliases from results var _r=DResolver.StripMemberSymbols(resToCheck); if(_r==null) return IsEqual(resToCheck,targetType); resToCheck = _r; targetType = DResolver.StripAliasSymbol(targetType); if (targetType is DSymbol) { var tpn = ((DSymbol)targetType).Definition as TemplateParameterNode; if (tpn!=null) { var par = tpn.Parent as DNode; if (par != null && par.TemplateParameters != null) { var dedParam = new DeducedTypeDictionary { ParameterOwner=par }; foreach (var tp in par.TemplateParameters) dedParam[tp.Name] = null; return new TemplateParameterDeduction(dedParam, ctxt).Handle(tpn.TemplateParameter, resToCheck); } } } _r = DResolver.StripMemberSymbols(targetType); if (_r == null) return false; targetType = _r; if (resToCheck is PrimitiveType && targetType is PrimitiveType) { var sr1 = (PrimitiveType)resToCheck; var sr2 = (PrimitiveType)targetType; if (sr1.TypeToken == sr2.TypeToken && sr1.Modifier == sr2.Modifier) return true; switch (sr2.TypeToken) { case DTokens.Int: return sr1.TypeToken == DTokens.Uint; case DTokens.Uint: return sr1.TypeToken == DTokens.Int; //TODO: Further types that can be converted into each other implicitly } } else if (resToCheck is UserDefinedType && targetType is UserDefinedType) return IsImplicitlyConvertible((UserDefinedType)resToCheck, (UserDefinedType)targetType); else if (resToCheck is DelegateType && targetType is DelegateType) { //TODO } else if (resToCheck is ArrayType && targetType is ArrayType) { var ar1 = (ArrayType)resToCheck; var ar2 = (ArrayType)targetType; // Key as well as value types must be matching! var ar1_n= ar1.KeyType==null; var ar2_n=ar2.KeyType==null; if (ar1_n != ar2_n) return false; if(ar1_n || IsImplicitlyConvertible(ar1.KeyType, ar2.KeyType, ctxt)) return IsImplicitlyConvertible(ar1.Base, ar2.Base, ctxt); } else if (resToCheck is TypeTuple && targetType is TypeTuple) { return true; } else if (resToCheck is ExpressionTuple && targetType is ExpressionTuple) { return true; } /*else if (resultToCheck is ExpressionValueResult && targetType is ExpressionValue) { return ((ExpressionValueResult)resultToCheck).Value.Equals(((ExpressionValueResult)targetType).Value); }*/ // http://dlang.org/type.html //TODO: Pointer to non-pointer / vice-versa checkability? -- Can it really be done implicitly? return false; }
private bool evalIsExpression_WithAliases(IsExpression isExpression, AbstractType typeToCheck) { /* * Note: It's needed to let the abstract ast scanner also scan through IsExpressions etc. * in order to find aliases and/or specified template parameters! */ var expectedTemplateParams = new TemplateParameter[isExpression.TemplateParameterList == null ? 1 : (isExpression.TemplateParameterList.Length + 1)]; expectedTemplateParams [0] = isExpression.ArtificialFirstSpecParam; if (expectedTemplateParams.Length > 1) { isExpression.TemplateParameterList.CopyTo(expectedTemplateParams, 1); } var tpl_params = new DeducedTypeDictionary(expectedTemplateParams); var tpd = new TemplateParameterDeduction(tpl_params, ctxt); bool retTrue = false; if (isExpression.EqualityTest) // 6. { // a) if (isExpression.TypeSpecialization != null) { tpd.EnforceTypeEqualityWhenDeducing = true; retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck); tpd.EnforceTypeEqualityWhenDeducing = false; } else // b) { var r = evalIsExpression_EvalSpecToken(isExpression, typeToCheck, true); retTrue = r.Item1; tpl_params[isExpression.ArtificialFirstSpecParam] = new TemplateParameterSymbol(isExpression.ArtificialFirstSpecParam, r.Item2); } } else // 5. { retTrue = tpd.Handle(isExpression.ArtificialFirstSpecParam, typeToCheck); } if (retTrue && isExpression.TemplateParameterList != null) { foreach (var p in isExpression.TemplateParameterList) { if (!tpd.Handle(p, tpl_params[p] != null ? tpl_params[p].Base : null)) { return(false); } } } if (retTrue) { foreach (var kv in tpl_params) { ctxt.CurrentContext.DeducedTemplateParameters[kv.Key] = kv.Value; } } return(retTrue); }
private bool TryHandleMethodArgumentTuple(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.. lastArgumentToTake = callArguments.Count - 1; // Also accept empty tuples.. if (callArguments.Count == 0) lastArgumentToTake = 0; } 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; } } } if (lastArgumentToTake < 0) { // An error occurred somewhere.. add = false; return true; } int argCountToHandle = lastArgumentToTake - currentArg; if (argCountToHandle > 0) argCountToHandle++; 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 TemplateParameterDeduction(DeducedTypeDictionary DeducedParameters, ResolutionContext ctxt) { this.ctxt = ctxt; this.TargetDictionary = DeducedParameters; }
void AppendTemplateParams(DNode dn, StringBuilder sb, int highlightTemplateParam = -1, DeducedTypeDictionary deducedTypes = null) { if (dn.TemplateParameters != null && dn.TemplateParameters.Length > 0) { sb.Append('('); for (int i = 0; i < dn.TemplateParameters.Length; i++) { var param = dn.TemplateParameters[i]; if (param != null) { var tps = deducedTypes != null ? deducedTypes[param] : null; string str; if (tps == null) { str = param.ToString(); } else if (tps.ParameterValue != null) { str = tps.ParameterValue.ToCode(); } else if (tps.Base != null) { str = tps.Base.ToCode(); } else { str = param.ToString(); } AppendFormat(DCodeToMarkup(str), sb, i != highlightTemplateParam ? FormatFlags.None : FormatFlags.Underline); sb.Append(','); } } RemoveLastChar(sb, ','); sb.Append(')'); } }
public string GenTooltipSignature(DNode dn, bool templateParamCompletion = false, int currentMethodParam = -1, ITypeDeclaration baseType = null, DeducedTypeDictionary deducedType = null) { var sb = new StringBuilder(); if (dn is DMethod) { S(dn as DMethod, sb, templateParamCompletion, currentMethodParam, baseType, deducedType); } else if (dn is DModule) { sb.Append("<i>(Module)</i> ").Append((dn as DModule).ModuleName); } else if (dn is DClassLike) { S(dn as DClassLike, sb, deducedType); } else if (dn != null) { AttributesTypeAndName(dn, sb, baseType, -1, deducedType); } return(sb.ToString()); }
private static bool DeduceParam(ResolutionContext ctxt, DSymbol overload, DeducedTypeDictionary deducedTypes, IEnumerator <ISemantic> argEnum, TemplateParameter expectedParam) { if (expectedParam is TemplateThisParameter && overload.Base != null) { var ttp = (TemplateThisParameter)expectedParam; // Get the type of the type of 'this' - so of the result that is the overload's base var t = DResolver.StripMemberSymbols(overload.Base); if (t == null || t.DeclarationOrExpressionBase == null) { return(false); } //TODO: Still not sure if it's ok to pass a type result to it // - looking at things like typeof(T) that shall return e.g. const(A) instead of A only. if (!CheckAndDeduceTypeAgainstTplParameter(ttp, t, deducedTypes, ctxt)) { return(false); } return(true); } // Used when no argument but default arg given bool useDefaultType = false; if (argEnum.MoveNext() || (useDefaultType = HasDefaultType(expectedParam))) { // On tuples, take all following arguments and pass them to the check function if (expectedParam is TemplateTupleParameter) { var tupleItems = new List <ISemantic>(); // A tuple must at least contain one item! tupleItems.Add(argEnum.Current); while (argEnum.MoveNext()) { tupleItems.Add(argEnum.Current); } if (!CheckAndDeduceTypeTuple((TemplateTupleParameter)expectedParam, tupleItems, deducedTypes, ctxt)) { return(false); } } else if (argEnum.Current != null) { if (!CheckAndDeduceTypeAgainstTplParameter(expectedParam, argEnum.Current, deducedTypes, ctxt)) { return(false); } } else if (useDefaultType && CheckAndDeduceTypeAgainstTplParameter(expectedParam, null, deducedTypes, ctxt)) { // It's legit - just do nothing } else { return(false); } } else if (expectedParam is TemplateTupleParameter) { if (!CheckAndDeduceTypeTuple(expectedParam as TemplateTupleParameter, null, deducedTypes, ctxt)) { return(false); } } // There might be too few args - but that doesn't mean that it's not correct - it's only required that all parameters got satisfied with a type else if (!deducedTypes.AllParamatersSatisfied) { return(false); } return(true); }
/// <summary> /// Checks results for implicit type convertability /// </summary> public static bool IsImplicitlyConvertible(ISemantic resultToCheck, AbstractType targetType, ResolutionContext ctxt = null) { var resToCheck = AbstractType.Get(resultToCheck); bool isVariable = resToCheck is MemberSymbol; // Initially remove aliases from results var _r = DResolver.StripMemberSymbols(resToCheck); if (_r == null) { return(IsEqual(resToCheck, targetType)); } resToCheck = _r; if (targetType is DSymbol) { var tpn = ((DSymbol)targetType).Definition as TemplateParameter.Node; if (tpn != null) { var par = tpn.Parent as DNode; if (par != null && par.TemplateParameters != null) { var dedParam = new DeducedTypeDictionary(par); return(new TemplateParameterDeduction(dedParam, ctxt).Handle(tpn.TemplateParameter, resToCheck)); } } } _r = DResolver.StripMemberSymbols(targetType); if (_r == null) { return(false); } targetType = _r; if (resToCheck is PrimitiveType && targetType is PrimitiveType) { var sr1 = (PrimitiveType)resToCheck; var sr2 = (PrimitiveType)targetType; //if (sr1.TypeToken == sr2.TypeToken /*&& sr1.Modifier == sr2.Modifier*/) // return true; return(IsPrimitiveTypeImplicitlyConvertible(sr1.TypeToken, sr2.TypeToken)); } else if (resToCheck is UserDefinedType && targetType is UserDefinedType) { return(IsImplicitlyConvertible((UserDefinedType)resToCheck, (UserDefinedType)targetType)); } else if (resToCheck is DelegateType && targetType is DelegateType) { return(IsEqual(resToCheck, targetType)); //TODO: Can non-equal delegates be converted into each other? } else if (resToCheck is ArrayType && targetType is ArrayType) { var ar1 = (ArrayType)resToCheck; var ar2 = (ArrayType)targetType; // Key as well as value types must be matching! var ar1_n = ar1.KeyType == null; var ar2_n = ar2.KeyType == null; if (ar1_n != ar2_n) { return(false); } if (ar1_n || IsImplicitlyConvertible(ar1.KeyType, ar2.KeyType, ctxt)) { return(IsImplicitlyConvertible(ar1.Base, ar2.Base, ctxt)); } } else if (resToCheck is DSymbol && targetType is DSymbol) { var r1 = resToCheck as DSymbol; var r2 = targetType as DSymbol; if (r1.Definition == r2.Definition) { //TODO: Compare template param deductions return(true); } } else if (resToCheck is DTuple && targetType is DTuple) { var tup1 = resToCheck as DTuple; var tup2 = resToCheck as DTuple; //TODO return(true); } /*else if (resultToCheck is ExpressionValueResult && targetType is ExpressionValue) * { * return ((ExpressionValueResult)resultToCheck).Value.Equals(((ExpressionValueResult)targetType).Value); * }*/ // http://dlang.org/type.html //TODO: Pointer to non-pointer / vice-versa checkability? -- Can it really be done implicitly? else if (!isVariable && resToCheck is ArrayType && targetType is PointerType && ((targetType = (targetType as PointerType).Base) is PrimitiveType) && DTokens.IsBasicType_Character((targetType as PrimitiveType).TypeToken)) { return((resultToCheck as ArrayType).IsString); } return(false); }
private static bool DeduceParams(IEnumerable<ISemantic> givenTemplateArguments, bool isMethodCall, ResolverContextStack ctxt, DSymbol overload, DNode tplNode, DeducedTypeDictionary deducedTypes) { bool isLegitOverload = true; var paramEnum = tplNode.TemplateParameters.GetEnumerator(); var args= givenTemplateArguments == null ? new List<ISemantic>() : givenTemplateArguments; if (overload is MemberSymbol && ((MemberSymbol)overload).IsUFCSResult){ var l = new List<ISemantic>(); l.Add(overload.Base); // The base stores the first argument('s type) l.AddRange(args); args = l; } var argEnum = args.GetEnumerator(); foreach (var expectedParam in tplNode.TemplateParameters) if (!DeduceParam(ctxt, overload, deducedTypes, argEnum, expectedParam)) { isLegitOverload = false; break; // Don't check further params if mismatch has been found } if (!isMethodCall && argEnum.MoveNext()) { // There are too many arguments passed - discard this overload isLegitOverload = false; } return isLegitOverload; }
/// <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> /// Checks results for implicit type convertability /// </summary> public static bool IsImplicitlyConvertible(ISemantic resultToCheck, AbstractType targetType, ResolutionContext ctxt=null) { var resToCheck = AbstractType.Get(resultToCheck); bool isVariable = resToCheck is MemberSymbol; // Initially remove aliases from results var _r=DResolver.StripMemberSymbols(resToCheck); if(_r==null) return IsEqual(resToCheck,targetType); resToCheck = _r; targetType = DResolver.StripAliasSymbol(targetType); if (targetType is DSymbol) { var tpn = ((DSymbol)targetType).Definition as TemplateParameter.Node; if (tpn!=null) { var par = tpn.Parent as DNode; if (par != null && par.TemplateParameters != null) { var dedParam = new DeducedTypeDictionary(par); return new TemplateParameterDeduction(dedParam, ctxt).Handle(tpn.TemplateParameter, resToCheck); } } } _r = DResolver.StripMemberSymbols(targetType); if (_r == null) return false; targetType = _r; if (resToCheck is PrimitiveType && targetType is PrimitiveType) { var sr1 = (PrimitiveType)resToCheck; var sr2 = (PrimitiveType)targetType; if (sr1.TypeToken == sr2.TypeToken /*&& sr1.Modifier == sr2.Modifier*/) return true; return ImplicitConvertabilityTable.Contains((sr2.TypeToken << 8) + sr1.TypeToken); } else if (resToCheck is UserDefinedType && targetType is UserDefinedType) return IsImplicitlyConvertible((UserDefinedType)resToCheck, (UserDefinedType)targetType); else if (resToCheck is DelegateType && targetType is DelegateType) return IsEqual(resToCheck, targetType); //TODO: Can non-equal delegates be converted into each other? else if (resToCheck is ArrayType && targetType is ArrayType) { var ar1 = (ArrayType)resToCheck; var ar2 = (ArrayType)targetType; // Key as well as value types must be matching! var ar1_n = ar1.KeyType == null; var ar2_n = ar2.KeyType == null; if (ar1_n != ar2_n) return false; if (ar1_n || IsImplicitlyConvertible(ar1.KeyType, ar2.KeyType, ctxt)) return IsImplicitlyConvertible(ar1.Base, ar2.Base, ctxt); } else if (resToCheck is DSymbol && targetType is DSymbol) { var r1 = resToCheck as DSymbol; var r2 = targetType as DSymbol; if (r1.Definition == r2.Definition) { //TODO: Compare template param deductions return true; } } else if (resToCheck is DTuple && targetType is DTuple) { var tup1 = resToCheck as DTuple; var tup2 = resToCheck as DTuple; //TODO return true; } /*else if (resultToCheck is ExpressionValueResult && targetType is ExpressionValue) { return ((ExpressionValueResult)resultToCheck).Value.Equals(((ExpressionValueResult)targetType).Value); }*/ // http://dlang.org/type.html //TODO: Pointer to non-pointer / vice-versa checkability? -- Can it really be done implicitly? else if (!isVariable && resToCheck is ArrayType && targetType is PointerType && ((targetType = (targetType as PointerType).Base) is PrimitiveType) && DTokens.IsBasicType_Character((targetType as PrimitiveType).TypeToken)) return (resultToCheck as ArrayType).IsString; return false; }
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; }
static bool CheckAndDeduceTypeAgainstTplParameter(TemplateParameter handledParameter, ISemantic argumentToCheck, DeducedTypeDictionary deducedTypes, ResolutionContext ctxt) { return new Templates.TemplateParameterDeduction(deducedTypes, ctxt).Handle(handledParameter, argumentToCheck); }
void S(DMethod dm, StringBuilder sb, bool templArgs = false, int curArg = -1, ITypeDeclaration baseType = null, DeducedTypeDictionary deducedTypes = null) { AttributesTypeAndName(dm, sb, baseType, templArgs ? curArg : -1, deducedTypes); // Parameters sb.Append ('('); if (dm.Parameters.Count != 0) { for (int i = 0; i < dm.Parameters.Count; i++) { sb.AppendLine (); sb.Append (" "); var parm = dm.Parameters [i] as DNode; var indexBackup = sb.Length; //TODO: Show deduced parameters AttributesTypeAndName(parm , sb); if (!templArgs && curArg == i) { //TODO: Optimize var contentToUnderline = sb.ToString(indexBackup, sb.Length-indexBackup); sb.Remove (indexBackup, contentToUnderline.Length); AppendFormat (contentToUnderline, sb, FormatFlags.Underline); } if (parm is DVariable && (parm as DVariable).Initializer != null) sb.Append(" = ").Append((parm as DVariable).Initializer.ToString()); sb.Append (','); } RemoveLastChar (sb, ','); sb.AppendLine (); } sb.Append (')'); }
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; if (overload == null) { if(!hasTemplateArgsPassed) filteredOverloads.Add(o); continue; } var tplNode = overload.Definition; // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params if (tplNode == null) { filteredOverloads.Add(overload); 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(overload); continue; } var deducedTypes = new DeducedTypeDictionary(overload); if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes)) { overload.DeducedTypes = deducedTypes.ToReadonly(); // Assign calculated types to final result filteredOverloads.Add(overload); } else overload.DeducedTypes = null; } return filteredOverloads; }
void S(DMethod dm, StringBuilder sb, bool templArgs = false, int curArg = -1, ITypeDeclaration baseType = null, DeducedTypeDictionary deducedTypes = null) { AttributesTypeAndName(dm, sb, baseType, templArgs ? curArg : -1, deducedTypes); AppendParameters(dm.Parameters, sb, templArgs, curArg); AppendConstraint(dm, sb); }
private static bool DeduceParams(IEnumerable<ISemantic> givenTemplateArguments, bool isMethodCall, ResolutionContext ctxt, DSymbol overload, DNode tplNode, DeducedTypeDictionary deducedTypes) { bool isLegitOverload = true; var paramEnum = tplNode.TemplateParameters.GetEnumerator(); var args = givenTemplateArguments ?? new List<ISemantic> (); var argEnum = args.GetEnumerator(); foreach (var expectedParam in tplNode.TemplateParameters) if (!DeduceParam(ctxt, overload, deducedTypes, argEnum, expectedParam)) { isLegitOverload = false; break; // Don't check further params if mismatch has been found } if (!isMethodCall && argEnum.MoveNext()) { // There are too many arguments passed - discard this overload isLegitOverload = false; } return isLegitOverload; }
void S(DClassLike dc, StringBuilder sb, DeducedTypeDictionary deducedTypes = null) { AppendAttributes(dc, sb); sb.Append(DCodeToMarkup(DTokens.GetTokenString(dc.ClassType))).Append(' '); sb.Append(DCodeToMarkup(dc.Name)); AppendTemplateParams(dc, sb, -1, deducedTypes); if (dc.BaseClasses != null && dc.BaseClasses.Count != 0) { sb.AppendLine(" : "); sb.Append(" "); foreach (var bc in dc.BaseClasses) sb.Append(' ').Append(DCodeToMarkup(bc.ToString())).Append(','); RemoveLastChar(sb, ','); } AppendConstraint(dc, sb); }
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); }
void AttributesTypeAndName(DNode dn, StringBuilder sb, ITypeDeclaration baseType = null, int highlightTemplateParam = -1, DeducedTypeDictionary deducedTypes = null) { AppendAttributes(dn, sb, baseType == null); if (dn.Type != null || baseType != null) sb.Append(DCodeToMarkup((baseType ?? dn.Type).ToString(true))).Append(' '); // Maybe highlight variables/method names? sb.Append(dn.Name); AppendTemplateParams(dn, sb, highlightTemplateParam, deducedTypes); }
void AppendTemplateParams(DNode dn, StringBuilder sb, int highlightTemplateParam = -1, DeducedTypeDictionary deducedTypes = null) { if (dn.TemplateParameters != null && dn.TemplateParameters.Length > 0) { sb.Append('('); for (int i = 0; i < dn.TemplateParameters.Length; i++) { var param = dn.TemplateParameters[i]; if (param != null) { var tps = deducedTypes != null ? deducedTypes[param] : null; string str; if (tps == null) str = param.ToString(); else if (tps.ParameterValue != null) str = tps.ParameterValue.ToCode(); else if (tps.Base != null) str = tps.Base.ToCode(); else str = param.ToString(); AppendFormat(DCodeToMarkup(str), sb, i != highlightTemplateParam ? FormatFlags.None : FormatFlags.Underline); sb.Append(','); } } RemoveLastChar(sb, ','); sb.Append(')'); } }
private static List<AbstractType> DeduceOverloads( IEnumerable<AbstractType> rawOverloadList, IEnumerable<ISemantic> givenTemplateArguments, bool isMethodCall, ResolverContextStack ctxt) { bool hasTemplateArgsPassed = givenTemplateArguments != null; if (hasTemplateArgsPassed) { var enumm = givenTemplateArguments.GetEnumerator(); hasTemplateArgsPassed = enumm.MoveNext(); enumm.Dispose(); } var filteredOverloads = new List<AbstractType>(); if (rawOverloadList == null) return filteredOverloads; foreach (var o in DResolver.StripAliasSymbols(rawOverloadList)) { if (!(o is DSymbol)) { if(!hasTemplateArgsPassed) filteredOverloads.Add(o); continue; } var overload = (DSymbol)o; var tplNode = overload.Definition; // Generically, the node should never be null -- except for TemplateParameterNodes that encapsule such params if (tplNode == null) { filteredOverloads.Add(overload); 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(overload); continue; } var deducedTypes = new DeducedTypeDictionary { ParameterOwner=tplNode }; foreach (var param in tplNode.TemplateParameters) deducedTypes[param.Name] = null; // Init all params to null to let deduction functions know what params there are if (DeduceParams(givenTemplateArguments, isMethodCall, ctxt, overload, tplNode, deducedTypes)) { overload.DeducedTypes = deducedTypes.ToReadonly(); // Assign calculated types to final result filteredOverloads.Add(overload); } else overload.DeducedTypes = null; } return filteredOverloads; }