Skip to content

Commit

Permalink
Generic impl selfs and associated fixes (FuelLabs#913)
Browse files Browse the repository at this point in the history
* Fix issue where function bodies were not being monomorphized.

* Implement part of generic impl self.

* Remove print statements.

* WIP

* Clippy warnings.

* Create a CompilerWarning to alert users when they have used a type parameter that is not in upper snake case form.

* Prep for change to how type ascriptions are used.

* Implement custom hash type.

* Fix non-deterministic bug.

* documentation

* Introduce types into Custom type.

* Make distinction between type params and type args in parser. Remove stale implementation of generic traits and generic supertraits.

* WIP

* Actually use type ascriptions.

* update

* Add actual TypeArguments.

* Have function application use TypeArgument.

* Improve how types are unified for structs.

* Evaluate type ascriptions recursively.

* Fix broken component.

* Done for structs, minus some edge cases.

* Fix type ascription usage.

* Fix bug with how enums are sized.

* Generic impl selfs works for enums.

* Turbofish works.

* fix bug

* Revert changes to lock file.

* Fix IR test cases.

* Fix bug.

* Tidy up test case.

* PR feedback.
  • Loading branch information
emilyaherbert authored Mar 25, 2022
1 parent f8a8ea6 commit dff4d64
Show file tree
Hide file tree
Showing 62 changed files with 3,171 additions and 1,670 deletions.
3 changes: 3 additions & 0 deletions forc-util/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ pub fn print_on_failure(silent_mode: bool, warnings: &[CompileWarning], errors:
errors.iter().for_each(format_err);
}

warnings.iter().for_each(format_warning);
errors.iter().for_each(format_err);

println_red_err(&format!(
" Aborting due to {} {}.",
e_len,
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/asm_generation/expression/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub(crate) fn convert_enum_instantiation_to_asm(
VirtualRegister::Constant(ConstantRegister::StackPointer),
"load $sp for enum pointer",
));
let ty = match resolve_type(decl.as_type(), &decl.span) {
let ty = match resolve_type(decl.type_id(), &decl.span) {
Ok(o) => o,
Err(e) => {
errors.push(e.into());
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/asm_generation/expression/subfield.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub(crate) fn get_subfields_for_layout(
// sorry
let leaked_ix: &'static str = Box::leak(Box::new(pos.to_string()));
let access_ident = Ident::new_with_override(leaked_ix, span.clone());
(*elem, access_ident.span().clone(), access_ident)
(elem.type_id, access_ident.span().clone(), access_ident)
})
.collect::<Vec<_>>(),
_ => {
Expand Down
1 change: 0 additions & 1 deletion sway-core/src/control_flow_analysis/dead_code_analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,6 @@ fn connect_expression(
};
Ok([then_expr, else_expr].concat())
}

TupleElemAccess { prefix, .. } => {
let prefix_idx = connect_expression(
&prefix.expression,
Expand Down
35 changes: 23 additions & 12 deletions sway-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ macro_rules! check_std_result {
}

macro_rules! assert_or_warn {
($bool_expr: expr, $warnings: ident, $span: expr, $warning: expr $(,)?) => {
($bool_expr: expr, $warnings: ident, $span: expr, $warning: expr $(,)?) => {{
if !$bool_expr {
use crate::error::CompileWarning;
$warnings.push(CompileWarning {
warning_content: $warning,
span: $span,
});
}
};
}};
}

/// Denotes a non-recoverable state
Expand All @@ -57,15 +57,6 @@ pub(crate) fn err<T>(warnings: Vec<CompileWarning>, errors: Vec<CompileError>) -
}
}

pub(crate) fn infallible<T>(res: CompileResult<T>) -> T {
match res.value {
Some(x) if res.errors.is_empty() && res.warnings.is_empty() => x,
_ => {
panic!("Internal compiler error: called `infallible` on a fallible compile result. Please report this bug: github.com/FuelLabs/Sway/issues")
}
}
}

/// Denotes a recovered or non-error state
pub(crate) fn ok<T>(
value: T,
Expand Down Expand Up @@ -227,6 +218,9 @@ pub enum Warning {
NonClassCaseStructName {
struct_name: Ident,
},
NonClassCaseTypeParameter {
name: Ident,
},
NonClassCaseTraitName {
name: Ident,
},
Expand Down Expand Up @@ -291,6 +285,14 @@ impl fmt::Display for Warning {
to_upper_camel_case(struct_name.as_str())
)
}
NonClassCaseTypeParameter { name } => {
write!(f,
"Type parameter \"{}\" is not idiomatic. TypeParameters should have a ClassCase name, like \
\"{}\".",
name,
to_upper_camel_case(name.as_str())
)
}
NonClassCaseTraitName { name } => {
write!(f,
"Trait name \"{}\" is not idiomatic. Traits should have a ClassCase name, like \
Expand Down Expand Up @@ -540,7 +542,7 @@ pub enum CompileError {
given: String,
expected: String,
},
#[error("\"{name}\" is not a trait, so it cannot be \"impl'd\". ")]
#[error("\"{name}\" is not a trait, so it cannot be \"impl'd\".")]
NotATrait { span: Span, name: Ident },
#[error("Trait \"{name}\" cannot be found in the current scope.")]
UnknownTrait { span: Span, name: Ident },
Expand All @@ -561,6 +563,10 @@ pub enum CompileError {
expected: usize,
span: Span,
},
#[error("\"{name}\" does not take type arguments.")]
DoesNotTakeTypeArguments { name: Ident, span: Span },
#[error("\"{name}\" needs type arguments.")]
NeedsTypeArguments { name: Ident, span: Span },
#[error(
"Struct with name \"{name}\" could not be found in this scope. Perhaps you need to import \
it?"
Expand Down Expand Up @@ -607,6 +613,8 @@ pub enum CompileError {
method_name: String,
type_name: String,
},
#[error("Duplicate definitions with name \"{method_name}\".")]
DuplicateMethodDefinitions { method_name: String, span: Span },
#[error("Module \"{name}\" could not be found.")]
ModuleNotFound { span: Span, name: String },
#[error("\"{name}\" is a {actually}, not a struct. Fields can only be accessed on structs.")]
Expand Down Expand Up @@ -1027,13 +1035,16 @@ impl CompileError {
FunctionNotAPartOfInterfaceSurface { span, .. } => span,
MissingInterfaceSurfaceMethods { span, .. } => span,
IncorrectNumberOfTypeArguments { span, .. } => span,
DoesNotTakeTypeArguments { span, .. } => span,
NeedsTypeArguments { span, .. } => span,
StructNotFound { span, .. } => span,
DeclaredNonStructAsStruct { span, .. } => span,
AccessedFieldOfNonStruct { span, .. } => span,
MethodOnNonValue { span, .. } => span,
StructMissingField { span, .. } => span,
StructDoesNotHaveField { span, .. } => span,
MethodNotFound { span, .. } => span,
DuplicateMethodDefinitions { span, .. } => span,
ModuleNotFound { span, .. } => span,
NotATuple { span, .. } => span,
NotAStruct { span, .. } => span,
Expand Down
3 changes: 2 additions & 1 deletion sway-core/src/optimize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2254,7 +2254,8 @@ fn convert_resolved_type(context: &mut Context, ast_type: &TypeInfo) -> Result<T
// aggregate which might not make as much sense as a dedicated Unit type.
Type::Unit
} else {
create_tuple_aggregate(context, fields.clone()).map(Type::Struct)?
let new_fields = fields.iter().map(|x| x.type_id).collect();
create_tuple_aggregate(context, new_fields).map(Type::Struct)?
}
}
TypeInfo::Custom { .. } => return Err("can't do custom types yet".into()),
Expand Down
2 changes: 2 additions & 0 deletions sway-core/src/parse_tree/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ mod reassignment;
mod storage;
mod r#struct;
mod r#trait;
mod type_argument;
mod type_parameter;
mod variable;

Expand All @@ -19,6 +20,7 @@ pub use r#struct::*;
pub use r#trait::*;
pub(crate) use reassignment::*;
pub use storage::*;
pub(crate) use type_argument::*;
pub(crate) use type_parameter::*;
pub use variable::*;

Expand Down
58 changes: 34 additions & 24 deletions sway-core/src/parse_tree/declaration/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ impl EnumDeclaration {
namespace: crate::semantic_analysis::NamespaceRef,
self_type: TypeId,
) -> TypedEnumDeclaration {
let mut variants_buf = vec![];
let mut errors = vec![];
let mut warnings = vec![];

let mut variants_buf = vec![];
let type_mapping = insert_type_parameters(&self.type_parameters);
for variant in &self.variants {
variants_buf.push(check!(
Expand All @@ -66,13 +66,13 @@ impl EnumDeclaration {
decl_inner: Pair<Rule>,
config: Option<&BuildConfig>,
) -> CompileResult<Self> {
let mut warnings = Vec::new();
let mut errors = Vec::new();
let path = config.map(|c| c.path());
let whole_enum_span = Span {
span: decl_inner.as_span(),
path: path.clone(),
path,
};
let mut warnings = Vec::new();
let mut errors = Vec::new();
let inner = decl_inner.into_inner();
let mut visibility = Visibility::Private;
let mut enum_name = None;
Expand Down Expand Up @@ -101,33 +101,42 @@ impl EnumDeclaration {
}
}

let type_parameters = TypeParameter::parse_from_type_params_and_where_clause(
type_params,
where_clause,
config,
)
.unwrap_or_else(&mut warnings, &mut errors, Vec::new);

// unwrap non-optional fields
let enum_name = enum_name.unwrap();
let name = check!(
ident::parse_from_pair(enum_name.clone(), config),
ident::parse_from_pair(enum_name.unwrap(), config),
return err(warnings, errors),
warnings,
errors
);
assert_or_warn!(
is_upper_camel_case(name.as_str()),
warnings,
Span {
span: enum_name.as_span(),
path,
},
name.span().clone(),
Warning::NonClassCaseEnumName {
enum_name: name.clone()
}
);

let type_parameters = check!(
TypeParameter::parse_from_type_params_and_where_clause(
type_params,
where_clause,
config,
),
vec!(),
warnings,
errors
);
for type_parameter in type_parameters.iter() {
assert_or_warn!(
is_upper_camel_case(type_parameter.name_ident.as_str()),
warnings,
type_parameter.name_ident.span().clone(),
Warning::NonClassCaseTypeParameter {
name: type_parameter.name_ident.clone()
}
);
}

let variants = check!(
EnumVariant::parse_from_pairs(variants, config),
Vec::new(),
Expand Down Expand Up @@ -157,17 +166,18 @@ impl EnumVariant {
span: Span,
type_mapping: &[(TypeParameter, TypeId)],
) -> CompileResult<TypedEnumVariant> {
let mut warnings = vec![];
let mut errors = vec![];
let enum_variant_type =
if let Some(matching_id) = self.r#type.matches_type_parameter(type_mapping) {
insert_type(TypeInfo::Ref(matching_id))
} else {
namespace
.resolve_type_with_self(self.r#type.clone(), self_type)
.unwrap_or_else(|_| {
errors.push(CompileError::UnknownType { span });
insert_type(TypeInfo::ErrorRecovery)
})
check!(
namespace.resolve_type_with_self(self.r#type.clone(), self_type, span, false),
insert_type(TypeInfo::ErrorRecovery),
warnings,
errors,
)
};
ok(
TypedEnumVariant {
Expand Down
Loading

0 comments on commit dff4d64

Please sign in to comment.