/// Evaluate the type of a record aggregate.
Evaluate the type of a record aggregate.
Evaluate the type of a record aggregate .
pub fn typeval_record_aggregate<'sbc, 'lazy: 'sbc, 'sb: 'lazy, 'ast: 'sb, 'ctx: 'sb>(
    tyc: &TypeckContext<'sbc, 'lazy, 'sb, 'ast, 'ctx>,
    _id: AggregateRef,
    hir: &hir::Aggregate,
    tyctx: &'ctx Ty,
) -> Result<&'ctx Ty> {
    let tyctx_flat = tyc.ctx.deref_named_type(tyctx)?;
    let record_ty = if let Ty::Record(ref ty) = *tyctx_flat {
        ty
    } else {
        unreachable!();
    };
    // Make sure the aggregate does not have more fields than the record.
    if hir.positional.len() > record_ty.fields.len() {
        tyc.emit(
            DiagBuilder2::error(format!(
                "aggregate `{}` has {} fields, but record `{}` only has {}",
                hir.span.extract(),
                hir.positional.len(),
                tyctx,
                record_ty.fields.len()
            ))
            .span(hir.span),
        );
        return Err(());
    }
    // Build a correspondence map between the fields of the aggregate and the
    // fields of the record type.
    let mut had_fails = false;
    #[derive(Copy, Clone, Debug)]
    enum FieldIndex {
        Pos(usize),
        Named(usize),
        Others,
    }
    let mut mapping = HashMap::<usize, FieldIndex>::new();
    let mut occupied = HashMap::<Name, Span>::new();
    for (index, &pos) in hir.positional.iter().enumerate() {
        mapping.insert(index, FieldIndex::Pos(index));
        occupied.insert(record_ty.fields[index].0, pos.span);
    }
    match hir.named {
        hir::AggregateKind::Both => (),
        hir::AggregateKind::Record(ref fields) => {
            for (agg_index, field) in fields.iter().enumerate() {
                for choice in &field.value.0 {
                    // Lookup the field name in the record type.
                    let type_index = match record_ty.lookup.get(&choice.value) {
                        Some(&i) => i,
                        None => {
                            tyc.emit(
                                DiagBuilder2::error(format!(
                                    "`{}` is not a field of {}",
                                    choice.value, tyctx
                                ))
                                .span(choice.span),
                            );
                            had_fails = true;
                            continue;
                        }
                    };
                    // Make sure it has not been mapped yet.
                    if let Some(existing) = occupied.insert(choice.value, choice.span) {
                        tyc.emit(
                            DiagBuilder2::error(format!(
                                "`{}` assigned multiple times",
                                choice.value
                            ))
                            .span(choice.span)
                            .add_note("Previous assignment was here:")
                            .span(existing),
                        );
                        had_fails = true;
                    }
                    // Keep track of the assignment.
                    mapping.insert(type_index, FieldIndex::Named(agg_index));
                }
            }
        }
        hir::AggregateKind::Array(..) => {
            tyc.emit(
                DiagBuilder2::error("expected a record aggregate, found an array aggregate")
                    .span(hir.span),
            );
            return Err(());
        }
    }
    if let Some(_others) = hir.others {
        let indices: Vec<_> = (0..record_ty.fields.len())
            .filter(|i| !mapping.contains_key(i))
            .collect();
        for type_index in indices {
            mapping.insert(type_index, FieldIndex::Others);
        }
    }
    debugln!("aggregate: record type mapping {:?}", mapping);
    // Forward the type context and check the type of elements.
    for (&type_index, &agg_index) in &mapping {
        match (|| {
            let ty = record_ty.fields[type_index].1.as_ref();
            match agg_index {
                FieldIndex::Pos(index) => {
                    let Spanned { value: id, span } = hir.positional[index];
                    tyc.ctx.set_type_context(id, ty);
                    let field_ty = tyc.lazy_typeval(id)?;
                    tyc.must_match(ty, field_ty, span);
                }
                FieldIndex::Named(index) => {
                    let Spanned { value: id, span } = hir.named.get(index);
                    tyc.ctx.set_type_context(id, ty);
                    let field_ty = tyc.lazy_typeval(id)?;
                    tyc.must_match(ty, field_ty, span);
                }
                FieldIndex::Others => {
                    let Spanned { value: id, span } = hir.others.unwrap();
                    tyc.ctx.set_type_context(id, ty);
                    let field_ty = tyc.lazy_typeval(id)?;
                    tyc.must_match(ty, field_ty, span);
                }
            }
            Ok(())
        })() {
            Ok(()) => (),
            Err(()) => had_fails = true,
        }
    }
    if had_fails {
        Err(())
    } else {
        Ok(tyctx)
    }
}
pub fn typeval_record_aggregate < ' sbc , ' lazy : ' sbc , ' sb : ' lazy , ' ast : ' sb , ' ctx : ' sb > ( tyc : & TypeckContext < ' sbc , ' lazy , ' sb , ' ast , ' ctx > , _id : AggregateRef , hir : & hir :: Aggregate , tyctx : & ' ctx Ty , ) -> Result < & ' ctx Ty > { let tyctx_flat = tyc . ctx . deref_named_type ( tyctx ) ? ; let record_ty = if let Ty :: Record ( ref ty ) = * tyctx_flat { ty } else { unreachable ! ( ) ; } ; // Make sure the aggregate does not have more fields than the record. if hir . positional . len ( ) > record_ty . fields . len ( ) { tyc . emit ( DiagBuilder2 :: error ( format ! ( " " hir span extract ( ) hir positional len ( ) tyctx record_ty fields len ( ) ) ) . span ( hir . span ) , ) ; return Err ( ( ) ) ; } // Build a correspondence map between the fields of the aggregate and the // fields of the record type. let mut had_fails = false ; # [ derive ( Copy Clone Debug ) ] enum FieldIndex { Pos ( usize ) , Named ( usize ) , Others , } let mut mapping = HashMap :: < usize , FieldIndex > :: new ( ) ; let mut occupied = HashMap :: < Name , Span > :: new ( ) ; for ( index , & pos ) in hir . positional . iter ( ) . enumerate ( ) { mapping . insert ( index , FieldIndex :: Pos ( index ) ) ; occupied . insert ( record_ty . fields [ index ] . 0 , pos . span ) ; } match hir . named { hir :: AggregateKind :: Both => ( ) , hir :: AggregateKind :: Record ( ref fields ) => { for ( agg_index , field ) in fields . iter ( ) . enumerate ( ) { for choice in & field . value . 0 { // Lookup the field name in the record type. let type_index = match record_ty . lookup . get ( & choice . value ) { Some ( & i ) => i , None => { tyc . emit ( DiagBuilder2 :: error ( format ! ( " " choice value tyctx ) ) . span ( choice . span ) , ) ; had_fails = true ; continue ; } } ; // Make sure it has not been mapped yet. if let Some ( existing ) = occupied . insert ( choice . value , choice . span ) { tyc . emit ( DiagBuilder2 :: error ( format ! ( " " choice value ) ) . span ( choice . span ) . add_note ( " " ) . span ( existing ) , ) ; had_fails = true ; } // Keep track of the assignment. mapping . insert ( type_index , FieldIndex :: Named ( agg_index ) ) ; } } } hir :: AggregateKind :: Array ( .. ) => { tyc . emit ( DiagBuilder2 :: error ( " " ) . span ( hir . span ) , ) ; return Err ( ( ) ) ; } } if let Some ( _others ) = hir . others { let indices : Vec < _ > = ( 0 .. record_ty . fields . len ( ) ) . filter ( | i | ! mapping . contains_key ( i ) ) . collect ( ) ; for type_index in indices { mapping . insert ( type_index , FieldIndex :: Others ) ; } } debugln ! ( " " mapping ) ; // Forward the type context and check the type of elements. for ( & type_index , & agg_index ) in & mapping { match ( | | { let ty = record_ty . fields [ type_index ] . 1 . as_ref ( ) ; match agg_index { FieldIndex :: Pos ( index ) => { let Spanned { value : id , span } = hir . positional [ index ] ; tyc . ctx . set_type_context ( id , ty ) ; let field_ty = tyc . lazy_typeval ( id ) ? ; tyc . must_match ( ty , field_ty , span ) ; } FieldIndex :: Named ( index ) => { let Spanned { value : id , span } = hir . named . get ( index ) ; tyc . ctx . set_type_context ( id , ty ) ; let field_ty = tyc . lazy_typeval ( id ) ? ; tyc . must_match ( ty , field_ty , span ) ; } FieldIndex :: Others => { let Spanned { value : id , span } = hir . others . unwrap ( ) ; tyc . ctx . set_type_context ( id , ty ) ; let field_ty = tyc . lazy_typeval ( id ) ? ; tyc . must_match ( ty , field_ty , span ) ; } } Ok ( ( ) ) } ) ( ) { Ok ( ( ) ) => ( ) , Err ( ( ) ) => had_fails = true , } } if had_fails { Err ( ( ) ) } else { Ok ( tyctx ) } }
Evaluate the type of a record aggregate.
Evaluate the type of a record aggregate .
tyc
&TypeckContext<'sbc, 'lazy, 'sb, 'ast, 'ctx>
_id
AggregateRef
hir
&hir::Aggregate
tyctx
&'ctx Ty