MethodSymbol CreateGhostOverload(PEModuleBuilder module, DiagnosticBag diagnostic, int pcount) { Debug.Assert(this.Parameters.Length > pcount); return(GhostMethodBuilder.CreateGhostOverload( this, this.ContainingType, module, diagnostic, ghostreturn: this.ReturnType, ghostparams: this.Parameters.Take(pcount), explicitOverride: null)); }
/// <summary> /// Synthesizes method overloads in case there are optional parameters which explicit default value cannot be resolved as a <see cref="ConstantValue"/>. /// </summary> /// <remarks> /// foo($a = [], $b = [1, 2, 3]) /// + foo() => foo([], [1, 2, 3) /// + foo($a) => foo($a, [1, 2, 3]) /// </remarks> protected IList <MethodSymbol> SynthesizeOverloadsWithOptionalParameters(PEModuleBuilder module, DiagnosticBag diagnostic) { List <MethodSymbol> list = null; var ps = this.Parameters; for (int i = 0; i < ps.Length; i++) { if (ps[i] is IPhpValue p && p.Initializer != null && ps[i].ExplicitDefaultConstantValue == null) // => ConstantValue couldn't be resolved for optional parameter { if (list == null) { list = new List <MethodSymbol>(); } if (this.ContainingType.IsInterface) { // TODO: we can't build instance method in an interface // - generate static extension method ? // - annotate parameter with attribute and the initializer value? // ? [Optional(EmptyArray)] // ? [Optional(array(1,2,3))] Debug.WriteLine($"we've lost parameter explicit default value {this.ContainingType.Name}::{this.RoutineName}, parameter ${ps[i].Name}"); } else { // create ghost stub foo(p0, .. pi-1) => foo(p0, .. , pN) list.Add(GhostMethodBuilder.CreateGhostOverload(this, module, diagnostic, i)); } } } return(list ?? (IList <MethodSymbol>)Array.Empty <MethodSymbol>()); }
void EmitTraitImplementations(Emit.PEModuleBuilder module) { foreach (var t in TraitUses) { foreach (var m in t.GetMembers().OfType <SynthesizedMethodSymbol>()) { Debug.Assert(m.ForwardedCall != null); module.SetMethodBody(m, MethodGenerator.GenerateMethodBody(module, m, il => { IPlace thisPlace = null; IPlace traitInstancePlace = null; IPlace ctxPlace; if (m.IsStatic) { // Template: return TRAIT.method(...) Debug.Assert(SpecialParameterSymbol.IsContextParameter(m.Parameters[0])); ctxPlace = new ParamPlace(m.Parameters[0]); } else { // Template: return this.<>trait.method(...) thisPlace = new ArgPlace(this, 0); // this ctxPlace = new FieldPlace(thisPlace, this.ContextStore, module); // this.<ctx> traitInstancePlace = new FieldPlace(thisPlace, t.TraitInstanceField, module); // this.<>trait } using (var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), module.Compilation.Options.OptimizationLevel, false, this, ctxPlace, thisPlace) { CallerType = this, }) { var forwarded_type = cg.EmitForwardCall(m.ForwardedCall, m, thisPlaceExplicit: traitInstancePlace); var target_type = m.ReturnType; cg.EmitConvert(forwarded_type, 0, target_type); // always (forwarded_type === target_type) cg.EmitRet(target_type); } }, null, DiagnosticBag.GetInstance(), false)); module.SynthesizedManager.AddMethod(this, m); // ghost stubs: // TODO: resolve this already in SourceTypeSymbol.GetMembers(), now it does not get overloaded properly var ps = m.Parameters; for (int i = 0; i < ps.Length; i++) { if (ps[i].HasUnmappedDefaultValue) // => ConstantValue couldn't be resolved for optional parameter { // create ghost stub foo(p0, .. pi-1) => foo(p0, .. , pN) GhostMethodBuilder.CreateGhostOverload(m, module, DiagnosticBag.GetInstance(), i); } } } } }
/// <summary> /// Synthesizes method overloads in case there are optional parameters which explicit default value cannot be resolved as a <see cref="ConstantValue"/>. /// </summary> /// <remarks> /// foo($a = [], $b = [1, 2, 3]) /// + foo() => foo([], [1, 2, 3) /// + foo($a) => foo($a, [1, 2, 3]) /// </remarks> protected IList <MethodSymbol> SynthesizeOverloadsWithOptionalParameters(PEModuleBuilder module, DiagnosticBag diagnostic) { List <MethodSymbol> list = null; var implparams = ImplicitParameters; var srcparams = SourceParameters; var implicitVarArgs = VarargsParam; for (int i = 0; i <= srcparams.Length; i++) // how many to be copied from {srcparams} { var isfake = /*srcparams[i - 1].IsFake*/ implicitVarArgs != null && i > 0 && srcparams[i - 1].Ordinal >= implicitVarArgs.Ordinal; // parameter was replaced with [params] var hasdefault = i < srcparams.Length && srcparams[i].HasUnmappedDefaultValue; // ConstantValue couldn't be resolved for optional parameter if (isfake || hasdefault) { if (this.ContainingType.IsInterface) { // TODO: we can't build instance method in an interface // - generate static extension method ? // - annotate parameter with attribute and the initializer value? // ? [Optional(EmptyArray)] // ? [Optional(array(1,2,3))] if (i < srcparams.Length) // always true { Debug.WriteLine($"we've lost parameter explicit default value {this.ContainingType.Name}::{this.RoutineName}, parameter ${srcparams[i].Name}"); } } else { // ghostparams := [...implparams, ...srcparams{0..i-1}] var ghostparams = new ParameterSymbol[implparams.Length + i]; implparams.CopyTo(ghostparams); Array.Copy(srcparams, 0, ghostparams, implparams.Length, i); // create ghost stub foo(p0, .. pi-1) => foo(p0, .. , pN) var ghost = GhostMethodBuilder.CreateGhostOverload( this, ContainingType, module, diagnostic, ReturnType, ghostparams); // if (list == null) { list = new List <MethodSymbol>(); } list.Add(ghost); } } } return(list ?? (IList <MethodSymbol>)Array.Empty <MethodSymbol>()); }
/// <summary> /// Synthesizes method overloads in case there are optional parameters which explicit default value cannot be resolved as a <see cref="ConstantValue"/>. /// </summary> /// <remarks> /// foo($a = [], $b = [1, 2, 3]) /// + foo() => foo([], [1, 2, 3) /// + foo($a) => foo($a, [1, 2, 3]) /// </remarks> protected IList <MethodSymbol> SynthesizeOverloadsWithOptionalParameters(PEModuleBuilder module, DiagnosticBag diagnostic) { List <MethodSymbol> list = null; var implparams = ImplicitParameters; var srcparams = SourceParameters; var implicitVarArgs = VarargsParam; for (int i = 0; i <= srcparams.Length; i++) // how many to be copied from {srcparams} { var isfake = /*srcparams[i - 1].IsFake*/ implicitVarArgs != null && i > 0 && srcparams[i - 1].Ordinal >= implicitVarArgs.Ordinal; // parameter was replaced with [params] var hasdefault = false; // i < srcparams.Length && srcparams[i].HasUnmappedDefaultValue(); // ConstantValue couldn't be resolved for optional parameter if (isfake || hasdefault) { if (this.ContainingType.IsInterface) { // we can't build instance method in an interface // CONSIDER: generate static extension method ? } else { // ghostparams := [...implparams, ...srcparams{0..i-1}] var ghostparams = ImmutableArray.CreateBuilder <ParameterSymbol>(implparams.Length + i); ghostparams.AddRange(implparams); ghostparams.AddRange(srcparams, i); // create ghost stub foo(p0, .. pi-1) => foo(p0, .. , pN) var ghost = GhostMethodBuilder.CreateGhostOverload( this, ContainingType, module, diagnostic, ReturnType, ghostparams.MoveToImmutable()); // if (list == null) { list = new List <MethodSymbol>(); } list.Add(ghost); } } } return(list ?? (IList <MethodSymbol>)Array.Empty <MethodSymbol>()); }
void CreateGhostOverload(PEModuleBuilder module, DiagnosticBag diagnostic, int pcount) { Debug.Assert(this.Parameters.Length > pcount); GhostMethodBuilder.CreateGhostOverload(this, this.ContainingType, module, diagnostic, this.ReturnType, this.Parameters.Take(pcount), null); }