/// <summary> /// Constructs most appropriate CLR return type of given routine. /// The method handles returning by alias, PHP7 return type, PHPDoc @return tag and result of flow analysis. /// In case the routine is an override or can be overriden, the CLR type is a value. /// </summary> internal static TypeSymbol ConstructClrReturnType(SourceRoutineSymbol routine) { var compilation = routine.DeclaringCompilation; // if the method is generator and can't be overriden then the return type must be generator // TODO: would not be necessary if GN_SGS got fixed (the routine could report the return type correctly itself) if (routine.IsGeneratorMethod()) { // if non-virtual -> return Generator directly if (IsNotOverriding(routine)) { return(compilation.CoreTypes.Generator); } else //can't be sure -> play safe with PhpValue { return(compilation.CoreTypes.PhpValue); } } // & if (routine.SyntaxSignature.AliasReturn) { return(compilation.CoreTypes.PhpAlias); } // : return type if (routine.SyntaxReturnType != null) { return(compilation.GetTypeFromTypeRef(routine.SyntaxReturnType)); } // for non virtual methods: if (IsNotOverriding(routine)) { // /** @return */ var typeCtx = routine.TypeRefContext; if (routine.PHPDocBlock != null && (compilation.Options.PhpDocTypes & PhpDocTypes.ReturnTypes) != 0) { var returnTag = routine.PHPDocBlock.Returns; if (returnTag != null && returnTag.TypeNames.Length != 0) { var tmask = PHPDoc.GetTypeMask(typeCtx, returnTag.TypeNamesArray, routine.GetNamingContext()); if (!tmask.IsVoid && !tmask.IsAnyType) { return(compilation.GetTypeFromTypeRef(typeCtx, tmask)); } } } // determine from code flow return(compilation.GetTypeFromTypeRef(typeCtx, routine.ResultTypeMask)); } else { // TODO: an override that respects the base? check routine.ResultTypeMask (flow analysis) and base implementation is it matches } // any value by default return(compilation.CoreTypes.PhpValue); }
public SourceGeneratorSymbol(SourceRoutineSymbol originalRoutine) : base(originalRoutine.ContainingType, string.Format(WellKnownPchpNames.GeneratorStateMachineNameFormatString, originalRoutine.RoutineName), isstatic: true, isvirtual: false, returnType: originalRoutine.DeclaringCompilation.CoreTypes.Void, ps: null) { Debug.Assert(originalRoutine.IsGeneratorMethod()); // Need to postpone settings the params because I can't access 'this' in base constructor call base.SetParameters(CreateParameters(originalRoutine)); }