Skip to content

Commit

Permalink
Unify AST nodes for parsed and typed impl self and impl trait. (#…
Browse files Browse the repository at this point in the history
…6251)

## Description

This PR unifies the AST representation for the parsed and typed `impl
self` and `impl trait` declarations.

Previously we had a parsed node for `impl self`, which was converted
into a `impl trait` typed node.
Now we are doing the same for the parsed nodes and using a unified
`ImplSelfOrTrait` node.

This will make it possible for
#6245 to store the parsed decl id
relationship for this node.

## Checklist

- [x] I have linked to any relevant issues.
- [ ] 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).
- [ ] If my change requires substantial documentation changes, I have
[requested support from the DevRel
team](https://github.com/FuelLabs/devrel-requests/issues/new/choose)
- [ ] I have added tests that prove my fix is effective or that my
feature works.
- [ ] 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.
  • Loading branch information
tritao authored Jul 10, 2024
1 parent 5456e62 commit db06515
Show file tree
Hide file tree
Showing 33 changed files with 301 additions and 357 deletions.
12 changes: 6 additions & 6 deletions forc-plugins/forc-doc/src/doc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::{
};
use sway_core::{
decl_engine::DeclEngine,
language::ty::{TyAstNodeContent, TyDecl, TyImplTrait, TyModule, TyProgram, TySubmodule},
language::ty::{TyAstNodeContent, TyDecl, TyImplSelfOrTrait, TyModule, TyProgram, TySubmodule},
Engines,
};
use sway_types::BaseIdent;
Expand All @@ -36,7 +36,7 @@ impl Documentation {
) -> Result<Documentation> {
// the first module prefix will always be the project name
let mut docs = Documentation::default();
let mut impl_traits: Vec<(TyImplTrait, ModuleInfo)> = Vec::new();
let mut impl_traits: Vec<(TyImplSelfOrTrait, ModuleInfo)> = Vec::new();
let module_info = ModuleInfo::from_ty_module(vec![project_name.to_owned()], None);
Documentation::from_ty_module(
engines.de(),
Expand Down Expand Up @@ -144,14 +144,14 @@ impl Documentation {
module_info: &ModuleInfo,
ty_module: &TyModule,
docs: &mut Documentation,
impl_traits: &mut Vec<(TyImplTrait, ModuleInfo)>,
impl_traits: &mut Vec<(TyImplSelfOrTrait, ModuleInfo)>,
document_private_items: bool,
) -> Result<()> {
for ast_node in &ty_module.all_nodes {
if let TyAstNodeContent::Declaration(ref decl) = ast_node.content {
if let TyDecl::ImplTrait(impl_trait) = decl {
if let TyDecl::ImplSelfOrTrait(impl_trait) = decl {
impl_traits.push((
(*decl_engine.get_impl_trait(&impl_trait.decl_id)).clone(),
(*decl_engine.get_impl_self_or_trait(&impl_trait.decl_id)).clone(),
module_info.clone(),
));
} else {
Expand All @@ -175,7 +175,7 @@ impl Documentation {
decl_engine: &DeclEngine,
typed_submodule: &TySubmodule,
docs: &mut Documentation,
impl_traits: &mut Vec<(TyImplTrait, ModuleInfo)>,
impl_traits: &mut Vec<(TyImplSelfOrTrait, ModuleInfo)>,
module_info: &ModuleInfo,
document_private_items: bool,
) -> Result<()> {
Expand Down
6 changes: 3 additions & 3 deletions forc-plugins/forc-doc/src/render/item/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use anyhow::Result;
use horrorshow::{box_html, Raw, RenderBox, Template};
use std::{collections::BTreeMap, fmt::Write};
use sway_core::language::ty::{
TyEnumVariant, TyImplTrait, TyStorageField, TyStructField, TyTraitFn, TyTraitItem,
TyEnumVariant, TyImplSelfOrTrait, TyStorageField, TyStructField, TyTraitFn, TyTraitItem,
};

/// The actual context of the item displayed by [ItemContext].
Expand Down Expand Up @@ -268,7 +268,7 @@ impl Renderable for Context {
#[derive(Debug, Clone)]
pub struct DocImplTrait {
pub impl_for_module: ModuleInfo,
pub impl_trait: TyImplTrait,
pub impl_trait: TyImplSelfOrTrait,
pub module_info_override: Option<Vec<String>>,
}

Expand Down Expand Up @@ -495,7 +495,7 @@ impl Renderable for ItemContext {
}
impl Renderable for DocImplTrait {
fn render(self, render_plan: RenderPlan) -> Result<Box<dyn RenderBox>> {
let TyImplTrait {
let TyImplSelfOrTrait {
trait_name,
items,
implementing_for,
Expand Down
2 changes: 1 addition & 1 deletion forc-plugins/forc-doc/src/render/title.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ impl DocBlock for TyDecl {
TyDecl::TraitDecl(_) => "trait",
TyDecl::AbiDecl(_) => "abi",
TyDecl::StorageDecl(_) => "contract_storage",
TyDecl::ImplTrait(_) => "impl_trait",
TyDecl::ImplSelfOrTrait(_) => "impl_trait",
TyDecl::FunctionDecl(_) => "fn",
TyDecl::ConstantDecl(_) => "constant",
TyDecl::TypeAliasDecl(_) => "type_alias",
Expand Down
6 changes: 3 additions & 3 deletions sway-core/src/control_flow_analysis/analyze_return_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,9 @@ fn connect_declaration<'eng: 'cfg, 'cfg>(
connect_typed_fn_decl(engines, &fn_decl, graph, entry_node)?;
Ok(leaves.to_vec())
}
ty::TyDecl::ImplTrait(ty::ImplTrait { decl_id, .. }) => {
let impl_trait = decl_engine.get_impl_trait(decl_id);
let ty::TyImplTrait {
ty::TyDecl::ImplSelfOrTrait(ty::ImplSelfOrTrait { decl_id, .. }) => {
let impl_trait = decl_engine.get_impl_self_or_trait(decl_id);
let ty::TyImplSelfOrTrait {
trait_name, items, ..
} = &*impl_trait;
let entry_node = graph.add_node(ControlFlowGraphNode::from_node(node));
Expand Down
26 changes: 15 additions & 11 deletions sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fn is_entry_point(node: &TyAstNode, decl_engine: &DeclEngine, tree_type: &TreeTy
struct_decl.visibility == Visibility::Public
}
TyAstNode {
content: TyAstNodeContent::Declaration(TyDecl::ImplTrait { .. }),
content: TyAstNodeContent::Declaration(TyDecl::ImplSelfOrTrait { .. }),
..
} => true,
TyAstNode {
Expand Down Expand Up @@ -198,7 +198,10 @@ impl<'cfg> ControlFlowGraph<'cfg> {
ControlFlowGraphNode::ProgramNode {
node:
ty::TyAstNode {
content: ty::TyAstNodeContent::Declaration(ty::TyDecl::ImplTrait { .. }),
content:
ty::TyAstNodeContent::Declaration(ty::TyDecl::ImplSelfOrTrait {
..
}),
..
},
..
Expand Down Expand Up @@ -632,9 +635,9 @@ fn connect_declaration<'eng: 'cfg, 'cfg>(
connect_enum_declaration(&enum_decl, *enum_ref.id(), graph, entry_node);
Ok(leaves.to_vec())
}
ty::TyDecl::ImplTrait(ty::ImplTrait { decl_id, .. }) => {
let impl_trait_decl = decl_engine.get_impl_trait(decl_id);
let ty::TyImplTrait {
ty::TyDecl::ImplSelfOrTrait(ty::ImplSelfOrTrait { decl_id, .. }) => {
let impl_trait_decl = decl_engine.get_impl_self_or_trait(decl_id);
let ty::TyImplSelfOrTrait {
trait_name,
items,
trait_decl_ref,
Expand Down Expand Up @@ -1168,8 +1171,8 @@ fn get_trait_fn_node_index<'a>(
.namespace
.find_trait_method(&struct_decl.call_path.suffix.clone().into(), &fn_decl.name))
}
ty::TyDecl::ImplTrait(ty::ImplTrait { decl_id, .. }) => {
let impl_trait = decl_engine.get_impl_trait(decl_id);
ty::TyDecl::ImplSelfOrTrait(ty::ImplSelfOrTrait { decl_id, .. }) => {
let impl_trait = decl_engine.get_impl_self_or_trait(decl_id);
Ok(graph
.namespace
.find_trait_method(&impl_trait.trait_name, &fn_decl.name))
Expand Down Expand Up @@ -2351,12 +2354,13 @@ fn construct_dead_code_warning_from_node(
}
ty::TyAstNode {
content:
ty::TyAstNodeContent::Declaration(ty::TyDecl::ImplTrait(ty::ImplTrait {
decl_id, ..
ty::TyAstNodeContent::Declaration(ty::TyDecl::ImplSelfOrTrait(ty::ImplSelfOrTrait {
decl_id,
..
})),
span,
} => {
let ty::TyImplTrait { .. } = &*decl_engine.get_impl_trait(decl_id);
let ty::TyImplSelfOrTrait { .. } = &*decl_engine.get_impl_self_or_trait(decl_id);
CompileWarning {
span: span.clone(),
warning_content: Warning::DeadDeclaration,
Expand Down Expand Up @@ -2554,7 +2558,7 @@ fn allow_dead_code_ast_node(decl_engine: &DeclEngine, node: &ty::TyAstNode) -> b
ty::TyDecl::TypeAliasDecl(ty::TypeAliasDecl { decl_id, .. }) => {
allow_dead_code(decl_engine.get_type_alias(decl_id).attributes.clone())
}
ty::TyDecl::ImplTrait { .. } => false,
ty::TyDecl::ImplSelfOrTrait { .. } => false,
ty::TyDecl::AbiDecl { .. } => false,
ty::TyDecl::GenericTypeForFunctionScope { .. } => false,
ty::TyDecl::ErrorRecovery(..) => false,
Expand Down
20 changes: 10 additions & 10 deletions sway-core/src/decl_engine/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::{
engine_threading::*,
language::ty::{
self, TyAbiDecl, TyConfigurableDecl, TyConstantDecl, TyEnumDecl, TyFunctionDecl,
TyImplTrait, TyStorageDecl, TyStructDecl, TyTraitDecl, TyTraitFn, TyTraitType,
TyImplSelfOrTrait, TyStorageDecl, TyStructDecl, TyTraitDecl, TyTraitFn, TyTraitType,
TyTypeAliasDecl,
},
};
Expand All @@ -25,7 +25,7 @@ pub struct DeclEngine {
trait_slab: ConcurrentSlab<TyTraitDecl>,
trait_fn_slab: ConcurrentSlab<TyTraitFn>,
trait_type_slab: ConcurrentSlab<TyTraitType>,
impl_trait_slab: ConcurrentSlab<TyImplTrait>,
impl_self_or_trait_slab: ConcurrentSlab<TyImplSelfOrTrait>,
struct_slab: ConcurrentSlab<TyStructDecl>,
storage_slab: ConcurrentSlab<TyStorageDecl>,
abi_slab: ConcurrentSlab<TyAbiDecl>,
Expand All @@ -44,7 +44,7 @@ impl Clone for DeclEngine {
trait_slab: self.trait_slab.clone(),
trait_fn_slab: self.trait_fn_slab.clone(),
trait_type_slab: self.trait_type_slab.clone(),
impl_trait_slab: self.impl_trait_slab.clone(),
impl_self_or_trait_slab: self.impl_self_or_trait_slab.clone(),
struct_slab: self.struct_slab.clone(),
storage_slab: self.storage_slab.clone(),
abi_slab: self.abi_slab.clone(),
Expand Down Expand Up @@ -105,7 +105,7 @@ decl_engine_get!(function_slab, ty::TyFunctionDecl);
decl_engine_get!(trait_slab, ty::TyTraitDecl);
decl_engine_get!(trait_fn_slab, ty::TyTraitFn);
decl_engine_get!(trait_type_slab, ty::TyTraitType);
decl_engine_get!(impl_trait_slab, ty::TyImplTrait);
decl_engine_get!(impl_self_or_trait_slab, ty::TyImplSelfOrTrait);
decl_engine_get!(struct_slab, ty::TyStructDecl);
decl_engine_get!(storage_slab, ty::TyStorageDecl);
decl_engine_get!(abi_slab, ty::TyAbiDecl);
Expand Down Expand Up @@ -142,7 +142,7 @@ decl_engine_insert!(function_slab, ty::TyFunctionDecl);
decl_engine_insert!(trait_slab, ty::TyTraitDecl);
decl_engine_insert!(trait_fn_slab, ty::TyTraitFn);
decl_engine_insert!(trait_type_slab, ty::TyTraitType);
decl_engine_insert!(impl_trait_slab, ty::TyImplTrait);
decl_engine_insert!(impl_self_or_trait_slab, ty::TyImplSelfOrTrait);
decl_engine_insert!(struct_slab, ty::TyStructDecl);
decl_engine_insert!(storage_slab, ty::TyStorageDecl);
decl_engine_insert!(abi_slab, ty::TyAbiDecl);
Expand All @@ -164,7 +164,7 @@ decl_engine_replace!(function_slab, ty::TyFunctionDecl);
decl_engine_replace!(trait_slab, ty::TyTraitDecl);
decl_engine_replace!(trait_fn_slab, ty::TyTraitFn);
decl_engine_replace!(trait_type_slab, ty::TyTraitType);
decl_engine_replace!(impl_trait_slab, ty::TyImplTrait);
decl_engine_replace!(impl_self_or_trait_slab, ty::TyImplSelfOrTrait);
decl_engine_replace!(struct_slab, ty::TyStructDecl);
decl_engine_replace!(storage_slab, ty::TyStorageDecl);
decl_engine_replace!(abi_slab, ty::TyAbiDecl);
Expand All @@ -182,7 +182,7 @@ decl_engine_index!(function_slab, ty::TyFunctionDecl);
decl_engine_index!(trait_slab, ty::TyTraitDecl);
decl_engine_index!(trait_fn_slab, ty::TyTraitFn);
decl_engine_index!(trait_type_slab, ty::TyTraitType);
decl_engine_index!(impl_trait_slab, ty::TyImplTrait);
decl_engine_index!(impl_self_or_trait_slab, ty::TyImplSelfOrTrait);
decl_engine_index!(struct_slab, ty::TyStructDecl);
decl_engine_index!(storage_slab, ty::TyStorageDecl);
decl_engine_index!(abi_slab, ty::TyAbiDecl);
Expand Down Expand Up @@ -228,7 +228,7 @@ decl_engine_clear_program!(
trait_slab, ty::TyTraitDecl;
trait_fn_slab, ty::TyTraitFn;
trait_type_slab, ty::TyTraitType;
impl_trait_slab, ty::TyImplTrait;
impl_self_or_trait_slab, ty::TyImplTrait;
struct_slab, ty::TyStructDecl;
storage_slab, ty::TyStorageDecl;
abi_slab, ty::TyAbiDecl;
Expand Down Expand Up @@ -360,9 +360,9 @@ impl DeclEngine {
///
/// Calling [DeclEngine][get] directly is equivalent to this method, but
/// this method adds additional syntax that some users may find helpful.
pub fn get_impl_trait<I>(&self, index: &I) -> Arc<ty::TyImplTrait>
pub fn get_impl_self_or_trait<I>(&self, index: &I) -> Arc<ty::TyImplSelfOrTrait>
where
DeclEngine: DeclEngineGet<I, ty::TyImplTrait>,
DeclEngine: DeclEngineGet<I, ty::TyImplSelfOrTrait>,
{
self.get(index)
}
Expand Down
4 changes: 2 additions & 2 deletions sway-core/src/decl_engine/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
decl_engine::*,
engine_threading::*,
language::ty::{
TyEnumDecl, TyFunctionDecl, TyImplTrait, TyStructDecl, TyTraitDecl, TyTraitFn,
TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait, TyStructDecl, TyTraitDecl, TyTraitFn,
TyTypeAliasDecl,
},
type_system::*,
Expand Down Expand Up @@ -167,7 +167,7 @@ impl SubstTypes for DeclId<TyTraitFn> {
}
}
}
impl SubstTypes for DeclId<TyImplTrait> {
impl SubstTypes for DeclId<TyImplSelfOrTrait> {
fn subst_inner(&mut self, type_mapping: &TypeSubstMap, engines: &Engines) -> HasChanges {
let decl_engine = engines.de();
let mut decl = (*decl_engine.get(self)).clone();
Expand Down
35 changes: 10 additions & 25 deletions sway-core/src/decl_engine/parsed_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
decl_engine::*,
language::parsed::{
AbiDeclaration, ConfigurableDeclaration, ConstantDeclaration, EnumDeclaration, EnumVariant,
FunctionDeclaration, ImplSelf, ImplTrait, StorageDeclaration, StructDeclaration,
FunctionDeclaration, ImplSelfOrTrait, StorageDeclaration, StructDeclaration,
TraitDeclaration, TraitFn, TraitTypeDeclaration, TypeAliasDeclaration, VariableDeclaration,
},
};
Expand All @@ -21,8 +21,7 @@ pub struct ParsedDeclEngine {
trait_slab: ConcurrentSlab<TraitDeclaration>,
trait_fn_slab: ConcurrentSlab<TraitFn>,
trait_type_slab: ConcurrentSlab<TraitTypeDeclaration>,
impl_trait_slab: ConcurrentSlab<ImplTrait>,
impl_self_slab: ConcurrentSlab<ImplSelf>,
impl_self_or_trait_slab: ConcurrentSlab<ImplSelfOrTrait>,
struct_slab: ConcurrentSlab<StructDeclaration>,
storage_slab: ConcurrentSlab<StorageDeclaration>,
abi_slab: ConcurrentSlab<AbiDeclaration>,
Expand Down Expand Up @@ -66,8 +65,7 @@ decl_engine_get!(function_slab, FunctionDeclaration);
decl_engine_get!(trait_slab, TraitDeclaration);
decl_engine_get!(trait_fn_slab, TraitFn);
decl_engine_get!(trait_type_slab, TraitTypeDeclaration);
decl_engine_get!(impl_trait_slab, ImplTrait);
decl_engine_get!(impl_self_slab, ImplSelf);
decl_engine_get!(impl_self_or_trait_slab, ImplSelfOrTrait);
decl_engine_get!(struct_slab, StructDeclaration);
decl_engine_get!(storage_slab, StorageDeclaration);
decl_engine_get!(abi_slab, AbiDeclaration);
Expand All @@ -92,8 +90,7 @@ decl_engine_insert!(function_slab, FunctionDeclaration);
decl_engine_insert!(trait_slab, TraitDeclaration);
decl_engine_insert!(trait_fn_slab, TraitFn);
decl_engine_insert!(trait_type_slab, TraitTypeDeclaration);
decl_engine_insert!(impl_trait_slab, ImplTrait);
decl_engine_insert!(impl_self_slab, ImplSelf);
decl_engine_insert!(impl_self_or_trait_slab, ImplSelfOrTrait);
decl_engine_insert!(struct_slab, StructDeclaration);
decl_engine_insert!(storage_slab, StorageDeclaration);
decl_engine_insert!(abi_slab, AbiDeclaration);
Expand Down Expand Up @@ -121,8 +118,7 @@ decl_engine_clear!(
trait_slab, TraitDeclaration;
trait_fn_slab, TraitFn;
trait_type_slab, TraitTypeDeclaration;
impl_trait_slab, ImplTrait;
impl_self_slab, ImplSelf;
impl_self_or_trait_slab, ImplTrait;
struct_slab, StructDeclaration;
storage_slab, StorageDeclaration;
abi_slab, AbiDeclaration;
Expand Down Expand Up @@ -158,8 +154,9 @@ decl_engine_clear_program!(
(trait_type_slab, |item: &TraitTypeDeclaration| item
.name
.span()),
(impl_trait_slab, |item: &ImplTrait| item.block_span.clone()),
(impl_self_slab, |item: &ImplSelf| item.block_span.clone()),
(impl_self_or_trait_slab, |item: &ImplSelfOrTrait| item
.block_span
.clone()),
(struct_slab, |item: &StructDeclaration| item.name.span()),
(storage_slab, |item: &StorageDeclaration| item.span.clone()),
(abi_slab, |item: &AbiDeclaration| item.name.span()),
Expand Down Expand Up @@ -212,21 +209,9 @@ impl ParsedDeclEngine {
///
/// Calling [ParsedDeclEngine][get] directly is equivalent to this method, but
/// this method adds additional syntax that some users may find helpful.
pub fn get_impl_trait<I>(&self, index: &I) -> Arc<ImplTrait>
pub fn get_impl_self_or_trait<I>(&self, index: &I) -> Arc<ImplSelfOrTrait>
where
ParsedDeclEngine: ParsedDeclEngineGet<I, ImplTrait>,
{
self.get(index)
}

/// Friendly helper method for calling the `get` method from the
/// implementation of [ParsedDeclEngineGet] for [ParsedDeclEngine]
///
/// Calling [ParsedDeclEngine][get] directly is equivalent to this method, but
/// this method adds additional syntax that some users may find helpful.
pub fn get_impl_self<I>(&self, index: &I) -> Arc<ImplSelf>
where
ParsedDeclEngine: ParsedDeclEngineGet<I, ImplSelf>,
ParsedDeclEngine: ParsedDeclEngineGet<I, ImplSelfOrTrait>,
{
self.get(index)
}
Expand Down
6 changes: 3 additions & 3 deletions sway-core/src/decl_engine/ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use crate::{
decl_engine::*,
engine_threading::*,
language::ty::{
self, TyAbiDecl, TyConstantDecl, TyEnumDecl, TyFunctionDecl, TyImplTrait, TyStorageDecl,
TyStructDecl, TyTraitDecl, TyTraitFn, TyTraitType,
self, TyAbiDecl, TyConstantDecl, TyEnumDecl, TyFunctionDecl, TyImplSelfOrTrait,
TyStorageDecl, TyStructDecl, TyTraitDecl, TyTraitFn, TyTraitType,
},
semantic_analysis::TypeCheckContext,
type_system::*,
Expand All @@ -40,7 +40,7 @@ pub type DeclRefFunction = DeclRef<DeclId<TyFunctionDecl>>;
pub type DeclRefTrait = DeclRef<DeclId<TyTraitDecl>>;
pub type DeclRefTraitFn = DeclRef<DeclId<TyTraitFn>>;
pub type DeclRefTraitType = DeclRef<DeclId<TyTraitType>>;
pub type DeclRefImplTrait = DeclRef<DeclId<TyImplTrait>>;
pub type DeclRefImplTrait = DeclRef<DeclId<TyImplSelfOrTrait>>;
pub type DeclRefStruct = DeclRef<DeclId<TyStructDecl>>;
pub type DeclRefStorage = DeclRef<DeclId<TyStorageDecl>>;
pub type DeclRefAbi = DeclRef<DeclId<TyAbiDecl>>;
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/ir_generation/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ impl<'eng> FnCompiler<'eng> {
decl_type: "type alias",
span: ast_node.span.clone(),
}),
ty::TyDecl::ImplTrait { .. } => {
ty::TyDecl::ImplSelfOrTrait { .. } => {
// XXX What if we ignore the trait implementation??? Potentially since
// we currently inline everything and below we 'recreate' the functions
// lazily as they are called, nothing needs to be done here. BUT!
Expand Down
Loading

0 comments on commit db06515

Please sign in to comment.