/// <summary> /// TODO: This is just a hack. We need to proper flow analysis /// to detect whether all code paths return a value. /// </summary> public static bool ContainsReturnStatement(BoundBlock boundBlock) { var walker = new ReturnStatementWalker(); walker.VisitBlock(boundBlock); return(walker._containsReturnStatement); }
private BoundNode BindFunctionDefinition(FunctionDefinitionSyntax declaration, Symbol parent) { BindAttributes(declaration.Attributes); var boundReturnType = Bind(declaration.ReturnType, x => BindType(x, parent)); var isQualifiedName = false; ContainerSymbol containerSymbol; Symbol functionOwner; switch (declaration.Name.Kind) { case SyntaxKind.IdentifierDeclarationName: containerSymbol = null; functionOwner = parent; break; case SyntaxKind.QualifiedDeclarationName: containerSymbol = LookupContainer(((QualifiedDeclarationNameSyntax)declaration.Name).Left); if (containerSymbol == null) { return(new BoundErrorNode()); } isQualifiedName = true; functionOwner = containerSymbol; break; default: throw new InvalidOperationException(); } var containerBinder = containerSymbol?.Binder ?? this; var symbolTable = containerBinder.LocalSymbols; var functionSymbol = symbolTable .SelectMany(x => x.Value) .OfType <SourceFunctionSymbol>() .FirstOrDefault(x => SyntaxFacts.HaveMatchingSignatures( x.DefinitionSyntax as FunctionSyntax ?? x.DeclarationSyntaxes[0], declaration)); if (functionSymbol != null) { if (functionSymbol.DefinitionSyntax != null) { Diagnostics.ReportSymbolRedefined(declaration.Name.SourceRange, functionSymbol); } else { functionSymbol.DefinitionSyntax = declaration; } } else { if (isQualifiedName) { Diagnostics.ReportUndeclaredFunctionInNamespaceOrClass((QualifiedDeclarationNameSyntax)declaration.Name); } functionSymbol = new SourceFunctionSymbol(declaration, parent, boundReturnType.TypeSymbol); containerBinder.AddSymbol(functionSymbol, declaration.Name.SourceRange, true); } if (declaration.Semantic != null) { Bind(declaration.Semantic, BindVariableQualifier); } var functionBinder = (functionOwner != null && (functionOwner.Kind == SymbolKind.Class || functionOwner.Kind == SymbolKind.Struct)) ? new StructMethodBinder(_sharedBinderState, this, (StructSymbol)functionOwner, functionSymbol) : new FunctionBinder(_sharedBinderState, this, functionSymbol); if (isQualifiedName) { functionBinder = new ContainedFunctionBinder(_sharedBinderState, functionBinder, containerSymbol.Binder, functionSymbol); } var boundParameters = BindParameters(declaration.ParameterList, functionBinder, functionSymbol); var boundBody = functionBinder.Bind(declaration.Body, x => functionBinder.BindBlock(x, functionSymbol)); if (boundReturnType.Type != IntrinsicTypes.Void && !ReturnStatementWalker.ContainsReturnStatement(boundBody)) { Diagnostics.Report(declaration.Name.SourceRange, DiagnosticId.ReturnExpected, functionSymbol.Name); } return(new BoundFunctionDefinition(functionSymbol, boundReturnType, boundParameters.ToImmutableArray(), boundBody)); }