/// Cast from one type to another, which also automatically derefs any Type::Ref() type.
/// if the cast is explicit (e.g. bytes32(bar) then implicit should be set to false.
Cast from one type to another, which also automatically derefs any Type::Ref() type.
if the cast is explicit  then implicit should be set to false.
Cast from one type to another which also automatically derefs any Type :: Ref () type . if the cast is explicit then implicit should be set to false .
pub fn cast(
    loc: &pt::Loc,
    expr: Expression,
    to: &Type,
    implicit: bool,
    ns: &Namespace,
    diagnostics: &mut Vec<Diagnostic>,
) -> Result<Expression, ()> {
    let from = expr.ty();
    if &from == to {
        return Ok(expr);
    }
    // First of all, if we have a ref then derefence it
    if let Type::Ref(r) = from {
        return cast(
            loc,
            Expression::Load(*loc, r.as_ref().clone(), Box::new(expr)),
            to,
            implicit,
            ns,
            diagnostics,
        );
    }
    // If it's a storage reference then load the value. The expr is the storage slot
    if let Type::StorageRef(r) = from {
        if let Expression::StorageBytesSubscript(_, _, _) = expr {
            return Ok(expr);
        } else {
            return cast(
                loc,
                Expression::StorageLoad(*loc, *r, Box::new(expr)),
                to,
                implicit,
                ns,
                diagnostics,
            );
        }
    }
    // Special case: when converting literal sign can change if it fits
    match (&expr, &from, to) {
        (&Expression::NumberLiteral(_, _, ref n), p, &Type::Uint(to_len)) if p.is_primitive() => {
            return if n.sign() == Sign::Minus {
                if implicit {
                    diagnostics.push(Diagnostic::type_error(
                        *loc,
                        format!(
                            "implicit conversion cannot change negative number to {}",
                            to.to_string(ns)
                        ),
                    ));
                    Err(())
                } else {
                    // Convert to little endian so most significant bytes are at the end; that way
                    // we can simply resize the vector to the right size
                    let mut bs = n.to_signed_bytes_le();
                    bs.resize(to_len as usize / 8, 0xff);
                    Ok(Expression::NumberLiteral(
                        *loc,
                        Type::Uint(to_len),
                        BigInt::from_bytes_le(Sign::Plus, &bs),
                    ))
                }
            } else if n.bits() >= to_len as u64 {
                diagnostics.push(Diagnostic::type_error(
                    *loc,
                    format!(
                        "implicit conversion would truncate from {} to {}",
                        from.to_string(ns),
                        to.to_string(ns)
                    ),
                ));
                Err(())
            } else {
                Ok(Expression::NumberLiteral(
                    *loc,
                    Type::Uint(to_len),
                    n.clone(),
                ))
            };
        }
        (&Expression::NumberLiteral(_, _, ref n), p, &Type::Int(to_len)) if p.is_primitive() => {
            return if n.bits() >= to_len as u64 {
                diagnostics.push(Diagnostic::type_error(
                    *loc,
                    format!(
                        "implicit conversion would truncate from {} to {}",
                        from.to_string(ns),
                        to.to_string(ns)
                    ),
                ));
                Err(())
            } else {
                Ok(Expression::NumberLiteral(
                    *loc,
                    Type::Int(to_len),
                    n.clone(),
                ))
            }
        }
        // Literal strings can be implicitly lengthened
        (&Expression::BytesLiteral(_, _, ref bs), p, &Type::Bytes(to_len)) if p.is_primitive() => {
            return if bs.len() > to_len as usize && implicit {
                diagnostics.push(Diagnostic::type_error(
                    *loc,
                    format!(
                        "implicit conversion would truncate from {} to {}",
                        from.to_string(ns),
                        to.to_string(ns)
                    ),
                ));
                Err(())
            } else {
                let mut bs = bs.to_owned();
                // Add zero's at the end as needed
                bs.resize(to_len as usize, 0);
                Ok(Expression::BytesLiteral(*loc, Type::Bytes(to_len), bs))
            };
        }
        (&Expression::BytesLiteral(loc, _, ref init), _, &Type::DynamicBytes)
        | (&Expression::BytesLiteral(loc, _, ref init), _, &Type::String) => {
            return Ok(Expression::AllocDynamicArray(
                loc,
                to.clone(),
                Box::new(Expression::NumberLiteral(
                    loc,
                    Type::Uint(32),
                    BigInt::from(init.len()),
                )),
                Some(init.clone()),
            ));
        }
        _ => (),
    };
    cast_types(loc, expr, from, to.clone(), implicit, ns, diagnostics)
}
pub fn cast ( loc : & pt :: Loc , expr : Expression , to : & Type , implicit : bool , ns : & Namespace , diagnostics : & mut Vec < Diagnostic > , ) -> Result < Expression , ( ) > { let from = expr . ty ( ) ; if & from == to { return Ok ( expr ) ; } // First of all, if we have a ref then derefence it if let Type :: Ref ( r ) = from { return cast ( loc , Expression :: Load ( * loc , r . as_ref ( ) . clone ( ) , Box :: new ( expr ) ) , to , implicit , ns , diagnostics , ) ; } // If it's a storage reference then load the value. The expr is the storage slot if let Type :: StorageRef ( r ) = from { if let Expression :: StorageBytesSubscript ( _ , _ , _ ) = expr { return Ok ( expr ) ; } else { return cast ( loc , Expression :: StorageLoad ( * loc , * r , Box :: new ( expr ) ) , to , implicit , ns , diagnostics , ) ; } } // Special case: when converting literal sign can change if it fits match ( & expr , & from , to ) { ( & Expression :: NumberLiteral ( _ , _ , ref n ) , p , & Type :: Uint ( to_len ) ) if p . is_primitive ( ) => { return if n . sign ( ) == Sign :: Minus { if implicit { diagnostics . push ( Diagnostic :: type_error ( * loc , format ! ( " " to to_string ( ns ) ) , ) ) ; Err ( ( ) ) } else { // Convert to little endian so most significant bytes are at the end; that way // we can simply resize the vector to the right size let mut bs = n . to_signed_bytes_le ( ) ; bs . resize ( to_len as usize / 8 , 0xff ) ; Ok ( Expression :: NumberLiteral ( * loc , Type :: Uint ( to_len ) , BigInt :: from_bytes_le ( Sign :: Plus , & bs ) , ) ) } } else if n . bits ( ) >= to_len as u64 { diagnostics . push ( Diagnostic :: type_error ( * loc , format ! ( " " from to_string ( ns ) to to_string ( ns ) ) , ) ) ; Err ( ( ) ) } else { Ok ( Expression :: NumberLiteral ( * loc , Type :: Uint ( to_len ) , n . clone ( ) , ) ) } ; } ( & Expression :: NumberLiteral ( _ , _ , ref n ) , p , & Type :: Int ( to_len ) ) if p . is_primitive ( ) => { return if n . bits ( ) >= to_len as u64 { diagnostics . push ( Diagnostic :: type_error ( * loc , format ! ( " " from to_string ( ns ) to to_string ( ns ) ) , ) ) ; Err ( ( ) ) } else { Ok ( Expression :: NumberLiteral ( * loc , Type :: Int ( to_len ) , n . clone ( ) , ) ) } } // Literal strings can be implicitly lengthened ( & Expression :: BytesLiteral ( _ , _ , ref bs ) , p , & Type :: Bytes ( to_len ) ) if p . is_primitive ( ) => { return if bs . len ( ) > to_len as usize && implicit { diagnostics . push ( Diagnostic :: type_error ( * loc , format ! ( " " from to_string ( ns ) to to_string ( ns ) ) , ) ) ; Err ( ( ) ) } else { let mut bs = bs . to_owned ( ) ; // Add zero's at the end as needed bs . resize ( to_len as usize , 0 ) ; Ok ( Expression :: BytesLiteral ( * loc , Type :: Bytes ( to_len ) , bs ) ) } ; } ( & Expression :: BytesLiteral ( loc , _ , ref init ) , _ , & Type :: DynamicBytes ) | ( & Expression :: BytesLiteral ( loc , _ , ref init ) , _ , & Type :: String ) => { return Ok ( Expression :: AllocDynamicArray ( loc , to . clone ( ) , Box :: new ( Expression :: NumberLiteral ( loc , Type :: Uint ( 32 ) , BigInt :: from ( init . len ( ) ) , ) ) , Some ( init . clone ( ) ) , ) ) ; } _ => ( ) , } ; cast_types ( loc , expr , from , to . clone ( ) , implicit , ns , diagnostics ) }
Cast from one type to another, which also automatically derefs any Type::Ref() type.
Cast from one type to another which also automatically derefs any Type :: Ref () type .
loc
&pt::Loc
expr
Expression
to
&Type
implicit
bool
ns
&Namespace
diagnostics
&mut Vec<Diagnostic>