Pchp.Core.Context
private SynthesizedPhpCtorSymbol(SourceTypeSymbol containingType, Accessibility accessibility, bool isInitFieldsOnly, MethodSymbol basector, MethodSymbol __construct, int paramsLimit = int.MaxValue) : base(containingType, WellKnownMemberNames.InstanceConstructorName, false, false, containingType.DeclaringCompilation.CoreTypes.Void, accessibility) { if (basector == null) { throw new ArgumentNullException(nameof(basector)); } _basector = basector; _phpconstruct = __construct; this.IsInitFieldsOnly = isInitFieldsOnly; // clone parameters from __construct ?? basector var template = (__construct ?? basector).Parameters; var ps = new List <ParameterSymbol>(template.Length) { new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0) // Context <ctx> }; // same parameters as PHP constructor for (int i = 0; i < template.Length && i < paramsLimit; i++) { var p = template[i]; if (!SpecialParameterSymbol.IsContextParameter(p)) { ps.Add(new SynthesizedParameterSymbol(this, p.Type, ps.Count, p.RefKind, p.Name, p.IsParams, explicitDefaultConstantValue: p.ExplicitDefaultConstantValue)); } } _parameters = ps.ToImmutableArray(); }
protected virtual IEnumerable <ParameterSymbol> CreateParameters(IEnumerable <ParameterSymbol> baseparams) { int index = 0; // Context <ctx> yield return(new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, index++)); if (IsInitFieldsOnly) { // DummyFieldsOnlyCtor _ yield return(new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.DummyFieldsOnlyCtor, "_", index++)); } // same parameters as PHP constructor foreach (var p in baseparams) { if (SpecialParameterSymbol.IsContextParameter(p)) { continue; } if (SpecialParameterSymbol.IsDummyFieldsOnlyCtorParameter(p)) { continue; } yield return(SynthesizedParameterSymbol.Create(this, p, index++)); } }
void EmitPhpCtor(MethodSymbol ctor, Emit.PEModuleBuilder module) { if (ctor == null) { return; // static class } Debug.Assert(ctor.MethodKind == MethodKind.Constructor); module.SetMethodBody(ctor, MethodGenerator.GenerateMethodBody(module, ctor, il => { Debug.Assert(SpecialParameterSymbol.IsContextParameter(ctor.Parameters[0])); var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), OptimizationLevel.Release, false, this, new ParamPlace(ctor.Parameters[0]), new ArgPlace(this, 0)); // call .phpnew var phpnew = this.InitializeInstanceMethod; cg.EmitPop(cg.EmitThisCall(phpnew, ctor)); // call __construct var phpctor = this.ResolvePhpCtor(true); cg.EmitPop(cg.EmitThisCall(phpctor, ctor)); Debug.Assert(ctor.ReturnsVoid); cg.EmitRet(ctor.ReturnType); }, null, DiagnosticBag.GetInstance(), false)); }
protected virtual IEnumerable <ParameterSymbol> CreateParameters(IEnumerable <ParameterSymbol> baseparams) { int index = 0; // Context <ctx> yield return(new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, index++)); if (IsInitFieldsOnly) { // QueryValue<DummyFieldsOnlyCtor> _ var dummy = DeclaringCompilation.CoreTypes.QueryValue_T.Symbol.Construct(DeclaringCompilation.CoreTypes.QueryValue_DummyFieldsOnlyCtor); yield return(new SpecialParameterSymbol(this, dummy, "_", index++)); } // same parameters as PHP constructor foreach (var p in baseparams) { if (SpecialParameterSymbol.IsContextParameter(p)) { continue; } if (SpecialParameterSymbol.IsQueryValueParameter(p, out var _, out var t) && t == SpecialParameterSymbol.QueryValueTypes.DummyFieldsOnlyCtor) { continue; } yield return(new SynthesizedParameterSymbol(this, p.Type, index++, p.RefKind, p.Name, p.IsParams, explicitDefaultConstantValue: p.ExplicitDefaultConstantValue)); } }
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); // NOTE: following is not needed anymore: //// ghost stubs: // ... 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> /// Gets place referring to <c>Pchp.Core.Context</c> object. /// </summary> internal virtual IPlace GetContextPlace() { if (_params.Length != 0 && SpecialParameterSymbol.IsContextParameter(_params[0])) { return(new ParamPlace(_params[0])); // <ctx> } else { return(null); } }
void EmitPhpCtors(ImmutableArray <MethodSymbol> instancectors, Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { foreach (SynthesizedPhpCtorSymbol ctor in instancectors) { module.SetMethodBody(ctor, MethodGenerator.GenerateMethodBody(module, ctor, il => { Debug.Assert(SpecialParameterSymbol.IsContextParameter(ctor.Parameters[0])); var cg = new CodeGenerator(il, module, diagnostics, OptimizationLevel.Release, false, this, new ParamPlace(ctor.Parameters[0]), new ArgPlace(this, 0)); Debug.Assert(ctor.BaseCtor != null); // base..ctor or this..ctor cg.EmitPop(cg.EmitThisCall(ctor.BaseCtor, ctor)); if (ctor.PhpConstructor == null) { // initialize <ctx> field, if field is declared within this type var ctxField = this.ContextStore; if (ctxField != null && object.ReferenceEquals((object)ctxField.ContainingType, this)) { var ctxFieldPlace = new FieldPlace(cg.ThisPlaceOpt, ctxField); // Debug.Assert(<ctx> != null) cg.EmitDebugAssertNotNull(cg.ContextPlaceOpt, "Context cannot be null."); // <this>.<ctx> = <ctx> ctxFieldPlace.EmitStorePrepare(il); cg.EmitLoadContext(); ctxFieldPlace.EmitStore(il); } // initialize class fields foreach (var fld in this.EnsureMembers().OfType <SourceFieldSymbol>().Where(fld => !fld.RequiresHolder && !fld.IsStatic && !fld.IsConst)) { fld.EmitInit(cg); } } else { Debug.Assert(ctor.BaseCtor.ContainingType == this); // this.__construct cg.EmitPop(cg.EmitThisCall(ctor.PhpConstructor, ctor)); } // ret Debug.Assert(ctor.ReturnsVoid); cg.EmitRet(ctor.ReturnType); }, null, diagnostics, false)); } }
/// <summary> /// Gets place referring to <c>Pchp.Core.Context</c> object. /// </summary> internal virtual IPlace GetContextPlace(PEModuleBuilder module) { var ps = ImplicitParameters; if (ps.Length != 0 && SpecialParameterSymbol.IsContextParameter(ps[0])) { return(new ParamPlace(ps[0])); // <ctx> } else { return(null); } }
/// <summary> /// Gets place referring to <c>Pchp.Core.Context</c> object. /// </summary> internal virtual IPlace GetContextPlace() { var ps = ImplicitParameters; if (ps.Count != 0 && SpecialParameterSymbol.IsContextParameter(ps[0])) { return(new ParamPlace(ps[0])); // <ctx> } else { return(null); } }
protected override IEnumerable <ParameterSymbol> CreateParameters(IEnumerable <ParameterSymbol> baseparams) { int index = 0; // same parameters as PHP constructor foreach (var p in baseparams) { if (!SpecialParameterSymbol.IsContextParameter(p)) { yield return(new SynthesizedParameterSymbol(this, p.Type, index++, p.RefKind, p.Name, p.IsParams, explicitDefaultConstantValue: p.ExplicitDefaultConstantValue)); } } }
protected virtual IEnumerable <ParameterSymbol> CreateParameters(IEnumerable <ParameterSymbol> baseparams) { int index = 0; // Context <ctx> yield return(new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, index++)); // same parameters as PHP constructor foreach (var p in baseparams) { if (!SpecialParameterSymbol.IsContextParameter(p)) { yield return(new SynthesizedParameterSymbol(this, p.Type, index++, p.RefKind, p.Name, p.IsParams, explicitDefaultConstantValue: p.ExplicitDefaultConstantValue)); } } }
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); } } }
void EmitPhpNew(SynthesizedPhpNewMethodSymbol phpnew, Emit.PEModuleBuilder module) { if (phpnew == null) { return; // static class } module.SetMethodBody(phpnew, MethodGenerator.GenerateMethodBody(module, phpnew, il => { Debug.Assert(SpecialParameterSymbol.IsContextParameter(phpnew.Parameters[0])); var cg = new CodeGenerator(il, module, DiagnosticBag.GetInstance(), OptimizationLevel.Release, false, this, new ParamPlace(phpnew.Parameters[0]), new ArgPlace(this, 0)); // initialize <ctx> field, // if field is declared within this type var ctxField = this.ContextField; if (ctxField != null && object.ReferenceEquals(ctxField.ContainingType, this)) { var ctxFieldPlace = new FieldPlace(cg.ThisPlaceOpt, ctxField); // Debug.Assert(<ctx> != null) cg.EmitDebugAssertNotNull(cg.ContextPlaceOpt, "Context cannot be null."); // <this>.<ctx> = <ctx> ctxFieldPlace.EmitStorePrepare(il); cg.EmitLoadContext(); ctxFieldPlace.EmitStore(il); } // initialize class fields, // default(PhpValue) is not a valid value, its TypeTable must not be null foreach (var fld in this.GetFieldsToEmit().OfType <SourceFieldSymbol>().Where(fld => !fld.IsStatic && !fld.IsConst)) { fld.EmitInit(cg); } // base..phpnew ?? base..ctor var basenew = phpnew.BasePhpNew; Debug.Assert(basenew != null); cg.EmitPop(cg.EmitThisCall(basenew, phpnew)); Debug.Assert(phpnew.ReturnsVoid); cg.EmitRet(true); }, null, DiagnosticBag.GetInstance(), false)); }
void EmitPhpCtors(ImmutableArray <MethodSymbol> instancectors, Emit.PEModuleBuilder module, DiagnosticBag diagnostics) { foreach (SynthesizedPhpCtorSymbol ctor in instancectors) { module.SetMethodBody(ctor, MethodGenerator.GenerateMethodBody(module, ctor, il => { if (ctor is SynthesizedParameterlessPhpCtorSymbol) { EmitParameterlessCtor(ctor, il, module, diagnostics); return; } Debug.Assert(SpecialParameterSymbol.IsContextParameter(ctor.Parameters[0])); var cg = new CodeGenerator(il, module, diagnostics, module.Compilation.Options.OptimizationLevel, false, this, new ParamPlace(ctor.Parameters[0]), new ArgPlace(this, 0)) { CallerType = this, ContainingFile = ContainingFile, }; Debug.Assert(ctor.BaseCtor != null); // base..ctor or this..ctor cg.EmitPop(cg.EmitForwardCall(ctor.BaseCtor, ctor)); if (ctor.PhpConstructor == null) { // initialize <ctx> field, if field is declared within this type var ctxField = this.ContextStore; if (ctxField != null && object.ReferenceEquals((object)ctxField.ContainingType, this)) { var ctxFieldPlace = new FieldPlace(cg.ThisPlaceOpt, ctxField, module); // Debug.Assert(<ctx> != null) cg.EmitDebugAssertNotNull(cg.ContextPlaceOpt, "Context cannot be null."); // <this>.<ctx> = <ctx> ctxFieldPlace.EmitStorePrepare(il); cg.EmitLoadContext(); ctxFieldPlace.EmitStore(il); } // trait specific: if (ctor is SynthesizedPhpTraitCtorSymbol tctor) { EmitTraitCtorInit(cg, tctor); } // trait instances: foreach (var t in this.TraitUses) { EmitTraitInstanceInit(cg, ctor, t); } // initialize instance fields: foreach (var f in this.GetMembers().OfType <IPhpPropertySymbol>().Where(f => f.FieldKind == PhpPropertyKind.InstanceField)) { Debug.Assert(f.ContainingStaticsHolder == null); f.EmitInit(cg); } } else { Debug.Assert(ctor.BaseCtor.ContainingType == this); // this.__construct cg.EmitPop(cg.EmitForwardCall(ctor.PhpConstructor, ctor)); } // ret Debug.Assert(ctor.ReturnsVoid); cg.EmitRet(ctor.ReturnType); }, null, diagnostics, false)); } }
void ResolveBaseCtorAndParameters() { if (!_parameters.IsDefaultOrEmpty) { return; } // var phpctor = this.PhpCtor; // this tells us what parameters are provided to resolve base .ctor that can be called var basephpnew = this.ContainingType.BaseType.PhpNewMethodSymbol; // base..phpnew() to be called if provided var basectors = (basephpnew != null) ? ImmutableArray.Create(basephpnew) : this.ContainingType.BaseType.InstanceConstructors .Where(c => c.DeclaredAccessibility != Accessibility.Private) .OrderByDescending(c => c.ParameterCount) // longest ctors first .AsImmutable(); // Context <ctx> var ps = new List <ParameterSymbol>(1) { new SpecialParameterSymbol(this, DeclaringCompilation.CoreTypes.Context, SpecialParameterSymbol.ContextName, 0) // Context <ctx> }; var givenparams = (phpctor != null) ? phpctor.Parameters.Where(p => !p.IsImplicitlyDeclared).ToArray() : EmptyArray <ParameterSymbol> .Instance; // find best matching basector foreach (var c in basectors) { var calledparams = c.Parameters.Where(p => !p.IsImplicitlyDeclared).ToArray(); if (CanBePassedTo(givenparams, calledparams)) { // we have found base constructor with most parameters we can call with given parameters _lazyBaseCtor = c; break; } } if (_lazyBaseCtor == null) { throw new InvalidOperationException("Base .ctor cannot be resolved with provided constructor."); } // Debug.Assert(SpecialParameterSymbol.IsContextParameter(ps[0])); Debug.Assert(_lazyBaseCtor != null && !_lazyBaseCtor.IsStatic); foreach (var p in _lazyBaseCtor.Parameters) { if (SpecialParameterSymbol.IsContextParameter(p)) { continue; } ps.Add(new SynthesizedParameterSymbol(this, p.Type, ps.Count, p.RefKind, p.Name, explicitDefaultConstantValue: p.ExplicitDefaultConstantValue)); } // _parameters = ps.AsImmutable(); }