use std::collections::BTreeMap;
use sway_error::warning::{CompileWarning, Warning};
use sway_types::{style::is_upper_camel_case, Spanned};
use crate::{
decl_engine::*,
error::*,
language::{parsed::*, ty, CallPath},
semantic_analysis::{declaration::insert_supertraits_into_namespace, Mode, TypeCheckContext},
type_system::*,
};
impl ty::TyTraitDeclaration {
pub(crate) fn type_check(
ctx: TypeCheckContext,
trait_decl: TraitDeclaration,
) -> CompileResult<Self> {
let mut warnings = Vec::new();
let mut errors = Vec::new();
let TraitDeclaration {
name,
type_parameters,
attributes,
interface_surface,
methods,
supertraits,
visibility,
span,
} = trait_decl;
if !is_upper_camel_case(name.as_str()) {
warnings.push(CompileWarning {
span: name.span(),
warning_content: Warning::NonClassCaseTraitName { name: name.clone() },
})
}
let type_engine = ctx.type_engine;
let decl_engine = ctx.decl_engine;
let engines = ctx.engines();
let self_type = type_engine.insert(decl_engine, TypeInfo::SelfType);
let mut trait_namespace = ctx.namespace.clone();
let mut ctx = ctx.scoped(&mut trait_namespace).with_self_type(self_type);
let new_type_parameters = check!(
TypeParameter::type_check_type_params(ctx.by_ref(), type_parameters, true),
return err(warnings, errors),
warnings,
errors
);
check!(
insert_supertraits_into_namespace(ctx.by_ref(), self_type, &supertraits),
return err(warnings, errors),
warnings,
errors
);
let mut new_interface_surface = vec![];
let mut dummy_interface_surface = vec![];
for method in interface_surface.into_iter() {
let method = check!(
ty::TyTraitFn::type_check(ctx.by_ref(), method),
return err(warnings, errors),
warnings,
errors
);
let decl_ref = decl_engine.insert(method.clone());
dummy_interface_surface.push(
decl_engine
.insert(method.to_dummy_func(Mode::NonAbi))
.with_parent(decl_engine, &decl_ref),
);
new_interface_surface.push(decl_ref);
}
check!(
ctx.namespace.insert_trait_implementation(
CallPath {
prefixes: vec![],
suffix: name.clone(),
is_absolute: false,
},
new_type_parameters.iter().map(|x| x.into()).collect(),
self_type,
&dummy_interface_surface,
&span,
false,
engines,
),
return err(warnings, errors),
warnings,
errors
);
let mut new_methods = vec![];
for method in methods.into_iter() {
let method = check!(
ty::TyFunctionDeclaration::type_check(ctx.by_ref(), method.clone(), true, false),
ty::TyFunctionDeclaration::error(method),
warnings,
errors
);
new_methods.push(decl_engine.insert(method));
}
let typed_trait_decl = ty::TyTraitDeclaration {
name,
type_parameters: new_type_parameters,
interface_surface: new_interface_surface,
methods: new_methods,
supertraits,
visibility,
attributes,
span,
};
ok(typed_trait_decl, warnings, errors)
}
pub(crate) fn retrieve_interface_surface_and_implemented_methods_for_type(
&self,
ctx: TypeCheckContext,
type_id: TypeId,
call_path: &CallPath,
) -> (MethodMap, MethodMap) {
let mut interface_surface_method_refs: MethodMap = BTreeMap::new();
let mut impld_method_refs: MethodMap = BTreeMap::new();
let ty::TyTraitDeclaration {
interface_surface, ..
} = self;
let engines = ctx.engines();
for decl_ref in interface_surface.iter() {
interface_surface_method_refs.insert(decl_ref.name.clone(), decl_ref.clone());
}
for decl_ref in ctx
.namespace
.get_methods_for_type_and_trait_name(engines, type_id, call_path)
.into_iter()
{
impld_method_refs.insert(decl_ref.name.clone(), decl_ref);
}
(interface_surface_method_refs, impld_method_refs)
}
pub(crate) fn retrieve_interface_surface_and_methods_and_implemented_methods_for_type(
&self,
ctx: TypeCheckContext,
type_id: TypeId,
call_path: &CallPath,
type_arguments: &[TypeArgument],
) -> CompileResult<(MethodMap, MethodMap, MethodMap)> {
let mut warnings = vec![];
let mut errors = vec![];
let mut interface_surface_method_refs: MethodMap = BTreeMap::new();
let mut method_refs: MethodMap = BTreeMap::new();
let mut impld_method_refs: MethodMap = BTreeMap::new();
let ty::TyTraitDeclaration {
interface_surface,
methods,
type_parameters,
..
} = self;
let decl_engine = ctx.decl_engine;
let engines = ctx.engines();
for decl_ref in interface_surface.iter() {
interface_surface_method_refs.insert(decl_ref.name.clone(), decl_ref.clone());
}
for decl_ref in methods.iter() {
method_refs.insert(decl_ref.name.clone(), decl_ref.clone());
}
let type_mapping = TypeSubstMap::from_type_parameters_and_type_arguments(
type_parameters
.iter()
.map(|type_param| type_param.type_id)
.collect(),
type_arguments
.iter()
.map(|type_arg| type_arg.type_id)
.collect(),
);
for decl_ref in ctx
.namespace
.get_methods_for_type_and_trait_name(engines, type_id, call_path)
.into_iter()
{
let mut method = check!(
CompileResult::from(decl_engine.get_function(&decl_ref, &call_path.span())),
return err(warnings, errors),
warnings,
errors
);
method.subst(&type_mapping, engines);
impld_method_refs.insert(
method.name.clone(),
decl_engine
.insert(method)
.with_parent(decl_engine, &decl_ref),
);
}
ok(
(
interface_surface_method_refs,
method_refs,
impld_method_refs,
),
warnings,
errors,
)
}
pub(crate) fn insert_interface_surface_and_methods_into_namespace(
&self,
ctx: TypeCheckContext,
trait_name: &CallPath,
type_arguments: &[TypeArgument],
type_id: TypeId,
) -> CompileResult<()> {
let mut warnings = vec![];
let mut errors = vec![];
let decl_engine = ctx.decl_engine;
let engines = ctx.engines();
let ty::TyTraitDeclaration {
interface_surface,
methods,
type_parameters,
..
} = self;
let mut all_methods = vec![];
let type_mapping = TypeSubstMap::from_type_parameters_and_type_arguments(
type_parameters
.iter()
.map(|type_param| type_param.type_id)
.collect(),
type_arguments
.iter()
.map(|type_arg| type_arg.type_id)
.collect(),
);
for decl_ref in interface_surface.iter() {
let mut method = check!(
CompileResult::from(decl_engine.get_trait_fn(decl_ref, &trait_name.span())),
continue,
warnings,
errors
);
method.replace_self_type(engines, type_id);
method.subst(&type_mapping, engines);
all_methods.push(
ctx.decl_engine
.insert(method.to_dummy_func(Mode::NonAbi))
.with_parent(ctx.decl_engine, decl_ref),
);
}
for decl_ref in methods.iter() {
let mut method = check!(
CompileResult::from(decl_engine.get_function(decl_ref, &trait_name.span())),
continue,
warnings,
errors
);
method.replace_self_type(engines, type_id);
method.subst(&type_mapping, engines);
all_methods.push(
ctx.decl_engine
.insert(method)
.with_parent(ctx.decl_engine, decl_ref),
);
}
ctx.namespace.insert_trait_implementation(
trait_name.clone(),
type_arguments.to_vec(),
type_id,
&all_methods,
&trait_name.span(),
false,
engines,
);
if errors.is_empty() {
ok((), warnings, errors)
} else {
err(warnings, errors)
}
}
}