use crate::{
decl_engine::parsed_id::ParsedDeclId,
language::{parsed::*, ty, CallPath},
semantic_analysis::*,
type_system::*,
Engines,
};
use ast_elements::type_parameter::GenericTypeParameter;
use sway_error::{
error::CompileError,
handler::{ErrorEmitted, Handler},
};
use symbol_collection_context::SymbolCollectionContext;
impl ty::TyStructDecl {
pub(crate) fn collect(
handler: &Handler,
engines: &Engines,
ctx: &mut SymbolCollectionContext,
decl_id: &ParsedDeclId<StructDeclaration>,
) -> Result<(), ErrorEmitted> {
let struct_decl = engines.pe().get_struct(decl_id);
let decl = Declaration::StructDeclaration(*decl_id);
ctx.insert_parsed_symbol(handler, engines, struct_decl.name.clone(), decl.clone())?;
let _ = ctx.scoped(
engines,
struct_decl.span.clone(),
Some(decl),
|_scoped_ctx| Ok(()),
);
Ok(())
}
pub(crate) fn type_check(
handler: &Handler,
mut ctx: TypeCheckContext,
decl: StructDeclaration,
) -> Result<Self, ErrorEmitted> {
let StructDeclaration {
name,
fields,
type_parameters,
visibility,
span,
attributes,
..
} = decl;
ctx.scoped(handler, Some(span.clone()), |ctx| {
let new_type_parameters = GenericTypeParameter::type_check_type_params(
handler,
ctx.by_ref(),
type_parameters,
None,
)?;
let mut new_fields = vec![];
let mut encountered_non_indexed_field = false;
for field in fields.into_iter() {
let ty_field = ty::TyStructField::type_check(handler, ctx.by_ref(), field)?;
if ty_field.attributes.indexed().is_some() && attributes.event().is_none() {
return Err(
handler.emit_err(CompileError::IndexedFieldInNonEventStruct {
field_name: ty_field.name.into(),
struct_name: name.into(),
}),
);
}
if ty_field.attributes.indexed().is_some() {
let abi_size_hint = ctx
.engines()
.te()
.get(ty_field.type_argument.type_id)
.abi_encode_size_hint(ctx.engines());
if encountered_non_indexed_field {
return Err(handler.emit_err(
CompileError::IndexedFieldMustPrecedeNonIndexedField {
field_name: ty_field.name.into(),
},
));
}
if !matches!(abi_size_hint, AbiEncodeSizeHint::Exact(_)) {
return Err(handler.emit_err(
CompileError::IndexedFieldIsNotFixedSizeABIType {
field_name: ty_field.name.into(),
},
));
}
} else {
encountered_non_indexed_field = true;
}
new_fields.push(ty_field);
}
let path = CallPath::ident_to_fullpath(name, ctx.namespace());
let decl = ty::TyStructDecl {
call_path: path,
generic_parameters: new_type_parameters,
fields: new_fields,
visibility,
span,
attributes,
};
Ok(decl)
})
}
}
impl ty::TyStructField {
pub(crate) fn type_check(
handler: &Handler,
ctx: TypeCheckContext,
field: StructField,
) -> Result<Self, ErrorEmitted> {
let type_engine = ctx.engines.te();
let mut type_argument = field.type_argument;
type_argument.type_id = ctx
.resolve_type(
handler,
type_argument.type_id,
&type_argument.span,
EnforceTypeArguments::Yes,
None,
)
.unwrap_or_else(|err| type_engine.id_of_error_recovery(err));
let field = ty::TyStructField {
visibility: field.visibility,
name: field.name,
span: field.span,
type_argument,
attributes: field.attributes,
};
Ok(field)
}
}
impl TypeCheckAnalysis for ty::TyStructDecl {
fn type_check_analyze(
&self,
_handler: &Handler,
_ctx: &mut TypeCheckAnalysisContext,
) -> Result<(), ErrorEmitted> {
Ok(())
}
}
impl TypeCheckFinalization for ty::TyStructDecl {
fn type_check_finalize(
&mut self,
_handler: &Handler,
_ctx: &mut TypeCheckFinalizationContext,
) -> Result<(), ErrorEmitted> {
Ok(())
}
}