You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: functions.rs
    path of file: ./repos/solang/src/sema
    
    the code of the file until where you have to start completion: // SPDX-License-Identifier: Apache-2.0

use super::{
    ast::{Diagnostic, Function, Mutability, Namespace, Parameter, StructType, Symbol, Type},
    contracts::is_base,
    diagnostics::Diagnostics,
    function_annotation::function_prototype_annotations,
    tags::resolve_tags,
    ContractDefinition,
};
use crate::sema::ast::ParameterAnnotation;
use crate::sema::function_annotation::unexpected_parameter_annotation;
use crate::sema::namespace::ResolveTypeContext;
use crate::Target;
use solang_parser::pt::{FunctionTy, Identifier};
use solang_parser::{
    doccomment::DocComment,
    pt,
    pt::{CodeLocation, OptionalCodeLocation},
};

/// Resolve function declaration in a contract
pub fn contract_function(
    contract: &ContractDefinition,
    func: &pt::FunctionDefinition,
    tags: &[DocComment],
    annotations: &[&pt::Annotation],
    file_no: usize,
    ns: &mut Namespace,
) -> Option<usize> {
    let mut success = true;
    let contract_no = contract.contract_no;

    // The parser allows constructors to have return values. This is so that we can give a
    // nicer error message than "returns unexpected"
    match func.ty {
        pt::FunctionTy::Function => {
            // Function name cannot be the same as the contract name
            if let Some(n) = &func.name {
                if n.name == ns.contracts[contract_no].id.name {
  
    
fn signatures() {
    use super::*;

    let mut ns = Namespace::new(Target::EVM);

    ns.contracts.push(ast::Contract::new(
        &pt::Identifier {
            name: "bar".to_string(),
            loc: pt::Loc::Implicit,
        },
        pt::ContractTy::Contract(pt::Loc::Implicit),
        Vec::new(),
        pt::Loc::Implicit,
    ));

    let fdecl = Function::new(
        pt::Loc::Implicit,
        pt::Loc::Implicit,
        pt::Identifier {
            name: "foo".to_owned(),
            loc: pt::Loc::Implicit,
        },
        None,
        vec![],
        pt::FunctionTy::Function,
        None,
        pt::Visibility::Public(None),
        vec![
            Parameter {
                loc: pt::Loc::Implicit,
                id: None,
                ty: Type::Uint(8),
                ty_loc: None,
                indexed: false,
                readonly: false,
                infinite_size: false,
                recursive: false,
                annotation: None,
            },
            Parameter {
                loc: pt::Loc::Implicit,
                id: None,
                ty: Type::Address(false),
                ty_loc: None,
                indexed: false,
                readonly: false,
                infinite_size: false,
                recursive: false,
                annotation: None,
            },
        ],
        Vec::new(),
        &ns,
    );

    assert_eq!(fdecl.signature, "foo(uint8,address)");
}