Skip to content

Commit

Permalink
Fixes associated types and re-enables tests. (FuelLabs#5169)
Browse files Browse the repository at this point in the history
## Description
Fixes associated types to work again.

Resolve methods now receive a self type. This is required because we
need the self type to resolve the `Self` associated types.

For the sake of usability added the `ctx.self_type()` back again.

Closes FuelLabs#5163

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.

---------

Co-authored-by: Joshua Batty <[email protected]>
Co-authored-by: IGI-111 <[email protected]>
  • Loading branch information
3 people authored Oct 6, 2023
1 parent b0ee854 commit d9050f4
Show file tree
Hide file tree
Showing 22 changed files with 229 additions and 84 deletions.
8 changes: 7 additions & 1 deletion sway-core/src/language/ty/declaration/trait_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub struct TyTraitType {
pub name: Ident,
pub attributes: transform::AttributesMap,
pub ty: Option<TypeArgument>,
pub implementing_type: TypeId,
pub span: Span,
}

Expand All @@ -21,7 +22,9 @@ impl Named for TyTraitType {
impl EqWithEngines for TyTraitType {}
impl PartialEqWithEngines for TyTraitType {
fn eq(&self, other: &Self, engines: &Engines) -> bool {
self.name == other.name && self.ty.eq(&other.ty, engines)
self.name == other.name
&& self.ty.eq(&other.ty, engines)
&& self.implementing_type.eq(&other.implementing_type)
}
}

Expand All @@ -30,13 +33,15 @@ impl HashWithEngines for TyTraitType {
let TyTraitType {
name,
ty,
implementing_type,
// these fields are not hashed because they aren't relevant/a
// reliable source of obj v. obj distinction
span: _,
attributes: _,
} = self;
name.hash(state);
ty.hash(state, engines);
implementing_type.hash(state);
}
}

Expand All @@ -45,6 +50,7 @@ impl SubstTypes for TyTraitType {
if let Some(ref mut ty) = self.ty {
ty.subst(type_mapping, engines);
}
self.implementing_type.subst(type_mapping, engines);
}
}

Expand Down
8 changes: 7 additions & 1 deletion sway-core/src/semantic_analysis/ast_node/code_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,13 @@ impl ty::TyCodeBlock {
let never_decl_opt = ctx
.namespace
.root()
.resolve_symbol(&Handler::default(), engines, &never_mod_path, &never_ident)
.resolve_symbol(
&Handler::default(),
engines,
&never_mod_path,
&never_ident,
None,
)
.ok();

if let Some(ty::TyDecl::EnumDecl(ty::EnumDecl {
Expand Down
8 changes: 5 additions & 3 deletions sway-core/src/semantic_analysis/ast_node/declaration/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,17 @@ impl ty::TyAbiDecl {
// so we don't support the case of calling a contract's own interface
// from itself. This is by design.

let self_type_param = TypeParameter::new_self_type(ctx.engines, name.span());
let self_type_id = self_type_param.type_id;

// A temporary namespace for checking within this scope.
let mut abi_namespace = ctx.namespace.clone();
let mut ctx = ctx
.scoped(&mut abi_namespace)
.with_abi_mode(AbiMode::ImplAbiFn(name.clone(), None));
.with_abi_mode(AbiMode::ImplAbiFn(name.clone(), None))
.with_self_type(Some(self_type_id));

// Insert the "self" type param into the namespace.
let self_type_param = TypeParameter::new_self_type(ctx.engines, name.span());
let self_type_id = self_type_param.type_id;
self_type_param.insert_self_type_into_namespace(handler, ctx.by_ref());

// Recursively make the interface surfaces and methods of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl TyDecl {
for supertrait in trait_decl.supertraits.iter_mut() {
let _ = ctx
.namespace
.resolve_call_path(handler, engines, &supertrait.name)
.resolve_call_path(handler, engines, &supertrait.name, ctx.self_type())
.map(|supertrait_decl| {
if let ty::TyDecl::TraitDecl(ty::TraitDecl {
name: supertrait_name,
Expand Down Expand Up @@ -175,10 +175,13 @@ impl TyDecl {
// insert those since we do not allow calling contract methods
// from contract methods
let emp_vec = vec![];
let impl_trait_items = if let Ok(ty::TyDecl::TraitDecl { .. }) = ctx
.namespace
.resolve_call_path(&Handler::default(), engines, &impl_trait.trait_name)
{
let impl_trait_items = if let Ok(ty::TyDecl::TraitDecl { .. }) =
ctx.namespace.resolve_call_path(
&Handler::default(),
engines,
&impl_trait.trait_name,
ctx.self_type(),
) {
&impl_trait.items
} else {
&emp_vec
Expand Down Expand Up @@ -259,7 +262,7 @@ impl TyDecl {
for supertrait in abi_decl.supertraits.iter_mut() {
let _ = ctx
.namespace
.resolve_call_path(handler, engines, &supertrait.name)
.resolve_call_path(handler, engines, &supertrait.name, ctx.self_type())
.map(|supertrait_decl| {
if let ty::TyDecl::TraitDecl(ty::TraitDecl {
name: supertrait_name,
Expand Down
35 changes: 26 additions & 9 deletions sway-core/src/semantic_analysis/ast_node/declaration/impl_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,19 @@ impl TyImplTrait {
let decl_engine = ctx.engines.de();
let engines = ctx.engines();

// Create a new type parameter for the Self type
let self_type_param = TypeParameter::new_self_type(engines, implementing_for.span());
let self_type_id = self_type_param.type_id;

// create a namespace for the impl
let mut impl_namespace = ctx.namespace.clone();
let mut ctx = ctx
.by_ref()
.scoped(&mut impl_namespace)
.with_const_shadowing_mode(ConstShadowingMode::ItemStyle)
.with_self_type(Some(self_type_id))
.allow_functions();

// Create a new type parameter for the Self type
let self_type_param = TypeParameter::new_self_type(engines, implementing_for.span());
let self_type_id = self_type_param.type_id;

// Type check the type parameters
let new_impl_type_parameters = TypeParameter::type_check_type_params(
handler,
Expand Down Expand Up @@ -118,11 +119,12 @@ impl TyImplTrait {
// Update the context
let mut ctx = ctx
.with_help_text("")
.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown));
.with_type_annotation(type_engine.insert(engines, TypeInfo::Unknown))
.with_self_type(Some(implementing_for.type_id));

let impl_trait = match ctx
.namespace
.resolve_call_path(handler, engines, &trait_name)
.resolve_call_path(handler, engines, &trait_name, ctx.self_type())
.ok()
{
Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => {
Expand Down Expand Up @@ -663,12 +665,27 @@ fn type_check_trait_implementation(
let decl_ref = decl_engine.insert(type_decl.clone());
impld_item_refs.insert((name, implementing_for), TyTraitItem::Type(decl_ref));

let old_type_decl_info = TypeInfo::TraitType {
let old_type_decl_info1 = TypeInfo::TraitType {
name: type_decl.name.clone(),
trait_type_id: implementing_for,
};
let old_type_decl_info2 = TypeInfo::TraitType {
name: type_decl.name.clone(),
trait_type_id: type_engine.insert(
engines,
TypeInfo::UnknownGeneric {
// Using Span::dummy just to match the type substitution, type is not used anywhere else.
name: Ident::new_with_override("Self".into(), Span::dummy()),
trait_constraints: VecSet(vec![]),
},
),
};
trait_type_mapping.extend(TypeSubstMap::from_type_parameters_and_type_arguments(
vec![type_engine.insert(engines, old_type_decl_info1)],
vec![type_decl.ty.clone().unwrap().type_id],
));
trait_type_mapping.extend(TypeSubstMap::from_type_parameters_and_type_arguments(
vec![type_engine.insert(engines, old_type_decl_info)],
vec![type_engine.insert(engines, old_type_decl_info2)],
vec![type_decl.ty.clone().unwrap().type_id],
));
}
Expand Down Expand Up @@ -1281,7 +1298,7 @@ fn handle_supertraits(

match ctx
.namespace
.resolve_call_path(handler, engines, &supertrait.name)
.resolve_call_path(handler, engines, &supertrait.name, ctx.self_type())
.ok()
{
Some(ty::TyDecl::TraitDecl(ty::TraitDecl { decl_id, .. })) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub(crate) fn insert_supertraits_into_namespace(

let decl = ctx
.namespace
.resolve_call_path(handler, engines, &supertrait.name)
.resolve_call_path(handler, engines, &supertrait.name, ctx.self_type())
.ok();

match (decl.clone(), supertraits_of) {
Expand Down
10 changes: 6 additions & 4 deletions sway-core/src/semantic_analysis/ast_node/declaration/trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,16 @@ impl TyTraitDecl {
let decl_engine = ctx.engines.de();
let engines = ctx.engines();

// A temporary namespace for checking within the trait's scope.
let mut trait_namespace = ctx.namespace.clone();
let mut ctx = ctx.scoped(&mut trait_namespace);

// Create a new type parameter for the "self type".
let self_type_param = TypeParameter::new_self_type(engines, name.span());
let self_type = self_type_param.type_id;

// A temporary namespace for checking within the trait's scope.
let mut trait_namespace = ctx.namespace.clone();
let mut ctx = ctx
.scoped(&mut trait_namespace)
.with_self_type(Some(self_type));

// Type check the type parameters.
let new_type_parameters = TypeParameter::type_check_type_params(
handler,
Expand Down
30 changes: 20 additions & 10 deletions sway-core/src/semantic_analysis/ast_node/declaration/trait_type.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use sway_error::handler::{ErrorEmitted, Handler};
use sway_error::{
error::CompileError,
handler::{ErrorEmitted, Handler},
};
use sway_types::Span;

use crate::{
language::{
Expand Down Expand Up @@ -41,19 +45,22 @@ impl ty::TyTraitType {
None
};

let trait_type = ty::TyTraitType {
name,
attributes,
ty,
span,
};

Ok(trait_type)
if let Some(implementing_type) = ctx.self_type() {
Ok(ty::TyTraitType {
name,
attributes,
ty,
implementing_type,
span,
})
} else {
Err(handler.emit_err(CompileError::Internal("Self type not provided.", span)))
}
}

/// Used to create a stubbed out constant when the constant fails to
/// compile, preventing cascading namespace errors.
pub(crate) fn error(_engines: &Engines, decl: parsed::TraitTypeDeclaration) -> TyTraitType {
pub(crate) fn error(engines: &Engines, decl: parsed::TraitTypeDeclaration) -> TyTraitType {
let parsed::TraitTypeDeclaration {
name,
attributes,
Expand All @@ -64,6 +71,9 @@ impl ty::TyTraitType {
name,
attributes,
ty: ty_opt,
implementing_type: engines
.te()
.insert(engines, TypeInfo::new_self_type(Span::dummy())),
span,
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ fn type_check_variable(

let typed_scrutinee = match ctx
.namespace
.resolve_symbol(&Handler::default(), engines, &name)
.resolve_symbol(&Handler::default(), engines, &name, ctx.self_type())
.ok()
{
// If this variable is a constant, then we turn it into a [TyScrutinee::Constant](ty::TyScrutinee::Constant).
Expand Down Expand Up @@ -214,9 +214,9 @@ fn type_check_struct(
let decl_engine = engines.de();

// find the struct definition from the name
let unknown_decl = ctx
.namespace
.resolve_symbol(handler, engines, &struct_name)?;
let unknown_decl =
ctx.namespace
.resolve_symbol(handler, engines, &struct_name, ctx.self_type())?;
let struct_ref = unknown_decl.to_struct_ref(handler, ctx.engines())?;
let mut struct_decl = decl_engine.get_struct(&struct_ref);

Expand Down Expand Up @@ -326,9 +326,12 @@ fn type_check_enum(
is_absolute: call_path.is_absolute,
};
// find the enum definition from the name
let unknown_decl = ctx
.namespace
.resolve_call_path(handler, engines, &enum_callpath)?;
let unknown_decl = ctx.namespace.resolve_call_path(
handler,
engines,
&enum_callpath,
ctx.self_type(),
)?;
let enum_ref = unknown_decl.to_enum_ref(handler, ctx.engines())?;
(
enum_callpath.span(),
Expand All @@ -338,9 +341,9 @@ fn type_check_enum(
}
None => {
// we may have an imported variant
let decl = ctx
.namespace
.resolve_call_path(handler, engines, &call_path)?;
let decl =
ctx.namespace
.resolve_call_path(handler, engines, &call_path, ctx.self_type())?;
if let TyDecl::EnumVariantDecl(ty::EnumVariantDecl { enum_ref, .. }) = decl.clone() {
(
call_path.suffix.span(),
Expand Down
Loading

0 comments on commit d9050f4

Please sign in to comment.