Skip to content

Commit

Permalink
Merge 3fe59d5 into 39421ea
Browse files Browse the repository at this point in the history
  • Loading branch information
ironcev authored Mar 11, 2024
2 parents 39421ea + 3fe59d5 commit f1c358d
Show file tree
Hide file tree
Showing 99 changed files with 2,608 additions and 822 deletions.
3 changes: 2 additions & 1 deletion sway-ast/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub enum Ty {
},
Ref {
ampersand_token: AmpersandToken,
// TODO-IG: Extend to support references to mutable values.
mut_token: Option<MutToken>,
ty: Box<Ty>,
},
Never {
Expand All @@ -45,6 +45,7 @@ impl Spanned for Ty {
Ty::Slice { slice_token, ty } => Span::join(slice_token.span(), ty.span()),
Ty::Ref {
ampersand_token,
mut_token: _,
ty,
} => Span::join(ampersand_token.span(), ty.span()),
Ty::Never { bang_token } => bang_token.span(),
Expand Down
11 changes: 9 additions & 2 deletions sway-core/src/abi_generation/evm_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,15 @@ pub fn abi_str(type_info: &TypeInfo, type_engine: &TypeEngine, decl_engine: &Dec
name,
trait_type_id: _,
} => format!("trait type {}", name),
Ref(ty) => {
format!("__ref {}", abi_str_type_arg(ty, type_engine, decl_engine)) // TODO-IG: No references in ABIs according to the RFC. Or we want to have them?
Ref {
to_mutable_value,
referenced_type,
} => {
format!(
"__ref {}{}", // TODO-IG: No references in ABIs according to the RFC. Or we want to have them?
if *to_mutable_value { "mut " } else { "" },
abi_str_type_arg(referenced_type, type_engine, decl_engine)
)
}
}
}
Expand Down
11 changes: 9 additions & 2 deletions sway-core/src/abi_generation/fuel_abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -869,8 +869,15 @@ impl TypeInfo {
name,
trait_type_id: _,
} => format!("trait type {}", name),
Ref(ty) => {
format!("__ref {}", ty.abi_str(ctx, type_engine, decl_engine)) // TODO-IG: No references in ABIs according to the RFC. Or we want to have them?
Ref {
to_mutable_value,
referenced_type,
} => {
format!(
"__ref {}{}", // TODO-IG: No references in ABIs according to the RFC. Or we want to have them?
if *to_mutable_value { "mut " } else { "" },
referenced_type.abi_str(ctx, type_engine, decl_engine)
)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion sway-core/src/ir_generation/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ fn convert_resolved_type(
TypeInfo::Alias { ty, .. } => {
convert_resolved_typeid(type_engine, decl_engine, context, &ty.type_id, span)?
}
TypeInfo::Ref(_) => Type::get_uint64(context),
TypeInfo::Ref { .. } => Type::get_uint64(context),
TypeInfo::Never => Type::get_never(context),

// Unsupported types which shouldn't exist in the AST after type checking and
Expand Down
5 changes: 4 additions & 1 deletion sway-core/src/ir_generation/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1409,7 +1409,10 @@ impl<'eng> FnCompiler<'eng> {
let reference_type = self.engines.te().get_unaliased(ast_expr.return_type);

let referenced_ast_type = match *reference_type {
TypeInfo::Ref(ref referenced_type) => Ok(referenced_type.type_id),
TypeInfo::Ref {
ref referenced_type,
..
} => Ok(referenced_type.type_id),
_ => Err(CompileError::Internal(
"Cannot dereference a non-reference expression.",
ast_expr.span.clone(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
decl_engine::*,
language::{
parsed::*,
ty::{self, TyCodeBlock, TyImplItem},
ty::{self, TyCodeBlock, TyImplItem, VariableMutability},
*,
},
namespace::{IsExtendingExistingImpl, IsImplSelf},
Expand Down Expand Up @@ -1862,7 +1862,9 @@ impl ty::TyExpression {
// loop cannot be endless.
while !current_type.is_array() {
match &*current_type {
TypeInfo::Ref(referenced_type) => {
TypeInfo::Ref {
referenced_type, ..
} => {
let referenced_type_id = referenced_type.type_id;

current_prefix_te = Box::new(ty::TyExpression {
Expand Down Expand Up @@ -2085,7 +2087,7 @@ impl ty::TyExpression {
fn type_check_ref(
handler: &Handler,
mut ctx: TypeCheckContext<'_>,
_to_mutable_value: bool,
to_mutable_value: bool,
value: Box<Expression>,
span: Span,
) -> Result<ty::TyExpression, ErrorEmitted> {
Expand All @@ -2100,7 +2102,9 @@ impl ty::TyExpression {
// without any expectations. That value will at the end not unify with the type
// annotation coming from the context and a type-mismatch error will be emitted.
let type_annotation = match &*type_engine.get(ctx.type_annotation()) {
TypeInfo::Ref(referenced_type) => referenced_type.type_id,
TypeInfo::Ref {
referenced_type, ..
} => referenced_type.type_id,
_ => type_engine.insert(engines, TypeInfo::Unknown, None),
};

Expand All @@ -2110,13 +2114,43 @@ impl ty::TyExpression {
.with_help_text("");

let expr_span = value.span();
let expr = ty::TyExpression::type_check(handler, ctx, *value)
.unwrap_or_else(|err| ty::TyExpression::error(err, expr_span.clone(), engines));
let expr = ty::TyExpression::type_check(handler, ctx, *value)?;

if to_mutable_value {
match expr.expression {
ty::TyExpressionVariant::ConstantExpression { .. } => {
return Err(
handler.emit_err(CompileError::RefMutCannotReferenceConstant {
constant: expr_span.str(),
span,
}),
)
}
ty::TyExpressionVariant::VariableExpression {
name: decl_name,
mutability: VariableMutability::Immutable,
..
} => {
return Err(handler.emit_err(
CompileError::RefMutCannotReferenceImmutableVariable { decl_name, span },
))
}
// TODO-IG: Check referencing parts of aggregates once reassignment is implemented.
_ => (),
}
};

let expr_type_argument: TypeArgument = expr.return_type.into();
let typed_expr = ty::TyExpression {
expression: ty::TyExpressionVariant::Ref(Box::new(expr)),
return_type: type_engine.insert(engines, TypeInfo::Ref(expr_type_argument), None),
return_type: type_engine.insert(
engines,
TypeInfo::Ref {
to_mutable_value,
referenced_type: expr_type_argument,
},
None,
),
span,
};

Expand All @@ -2138,9 +2172,18 @@ impl ty::TyExpression {
// reference to the expected type.
// Otherwise, we pass a new `TypeInfo::Unknown` as the annotation, to allow the `expr`
// to be evaluated without any expectations.
// Since `&mut T` coerces into `&T` we always go with a lesser expectation, `&T`.
// Thus, `to_mutable_value` is set to false.
let type_annotation = match &*type_engine.get(ctx.type_annotation()) {
TypeInfo::Unknown => type_engine.insert(engines, TypeInfo::Unknown, None),
_ => type_engine.insert(engines, TypeInfo::Ref(ctx.type_annotation().into()), None),
_ => type_engine.insert(
engines,
TypeInfo::Ref {
to_mutable_value: false,
referenced_type: ctx.type_annotation().into(),
},
None,
),
};

let deref_ctx = ctx
Expand All @@ -2155,7 +2198,10 @@ impl ty::TyExpression {
let expr_type = type_engine.get(expr.return_type);
let return_type = match *expr_type {
TypeInfo::ErrorRecovery(_) => Ok(expr.return_type), // Just forward the error return type.
TypeInfo::Ref(ref exp) => Ok(exp.type_id), // Get the referenced type.
TypeInfo::Ref {
referenced_type: ref exp,
..
} => Ok(exp.type_id), // Get the referenced type.
_ => Err(
handler.emit_err(CompileError::ExpressionCannotBeDereferenced {
expression_type: engines.help_out(expr.return_type).to_string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ pub(crate) fn instantiate_struct_field_access(
// loop cannot be endless.
while !current_type.is_struct() {
match &*current_type {
TypeInfo::Ref(referenced_type) => {
TypeInfo::Ref {
referenced_type, ..
} => {
let referenced_type_id = referenced_type.type_id;

current_prefix_te = Box::new(ty::TyExpression {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ pub(crate) fn instantiate_tuple_index_access(
// loop cannot be endless.
while !current_type.is_tuple() {
match &*current_type {
TypeInfo::Ref(referenced_type) => {
TypeInfo::Ref {
referenced_type, ..
} => {
let referenced_type_id = referenced_type.type_id;

current_prefix_te = Box::new(ty::TyExpression {
Expand Down
59 changes: 55 additions & 4 deletions sway-core/src/semantic_analysis/namespace/trait_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
CallPath,
},
type_system::{SubstTypes, TypeId},
TraitConstraint, TypeArgument, TypeInfo, TypeSubstMap, UnifyCheck,
TraitConstraint, TypeArgument, TypeEngine, TypeInfo, TypeSubstMap, UnifyCheck,
};

use super::TryInsertingTraitImplOnFailure;
Expand Down Expand Up @@ -195,7 +195,7 @@ impl TraitMap {
value:
TraitValue {
trait_items: map_trait_items,
..
impl_span: existing_impl_span,
},
} in self.trait_impls.iter()
{
Expand All @@ -209,7 +209,57 @@ impl TraitMap {
} = map_trait_name;

let unify_checker = UnifyCheck::non_generic_constraint_subset(engines);
let types_are_subset = unify_checker.check(type_id, *map_type_id);

// Types are subset if the `type_id` that we want to insert can unify with the
// existing `map_type_id`. In addition we need to additionally check for the case of
// `&mut <type>` and `&<type>`.
let types_are_subset = unify_checker.check(type_id, *map_type_id)
&& is_unified_type_subset(engines.te(), type_id, *map_type_id);

/// `left` can unify into `right`. Additionally we need to check subset condition in case of
/// [TypeInfo::Ref] types. Although `&mut <type>` can unify with `&<type>`
/// when it comes to trait and self impls, we considered them to be different types.
/// E.g., we can have `impl Foo for &T` and at the same time `impl Foo for &mut T`.
/// Or in general, `impl Foo for & &mut .. &T` is different type then, e.g., `impl Foo for &mut & .. &mut T`.
fn is_unified_type_subset(
type_engine: &TypeEngine,
mut left: TypeId,
mut right: TypeId,
) -> bool {
// The loop cannot be endless, because at the end we must hit a referenced type which is not
// a reference.
loop {
let left_ty_info = &*type_engine.get_unaliased(left);
let right_ty_info = &*type_engine.get_unaliased(right);
match (left_ty_info, right_ty_info) {
(
TypeInfo::Ref {
to_mutable_value: l_to_mut,
..
},
TypeInfo::Ref {
to_mutable_value: r_to_mut,
..
},
) if *l_to_mut != *r_to_mut => return false, // Different mutability means not subset.
(
TypeInfo::Ref {
referenced_type: l_ty,
..
},
TypeInfo::Ref {
referenced_type: r_ty,
..
},
) => {
left = l_ty.type_id;
right = r_ty.type_id;
}
_ => return true,
}
}
}

let mut traits_are_subset = true;
if *map_trait_name_suffix != trait_name.suffix
|| map_trait_type_args.len() != trait_type_args.len()
Expand All @@ -232,7 +282,7 @@ impl TraitMap {
{
let trait_name_str = format!(
"{}{}",
trait_name.suffix,
trait_name,
if trait_type_args.is_empty() {
String::new()
} else {
Expand All @@ -249,6 +299,7 @@ impl TraitMap {
handler.emit_err(CompileError::ConflictingImplsForTraitAndType {
trait_name: trait_name_str,
type_implementing_for: engines.help_out(type_id).to_string(),
existing_impl_span: existing_impl_span.clone(),
second_impl_span: impl_span.clone(),
});
} else if types_are_subset
Expand Down
6 changes: 1 addition & 5 deletions sway-core/src/semantic_analysis/node_dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,7 @@ fn type_info_name(type_info: &TypeInfo) -> String {
TypeInfo::Slice(..) => "__slice",
TypeInfo::Alias { .. } => "alias",
TypeInfo::TraitType { .. } => "trait type",
TypeInfo::Ref(..) => "reference type",
TypeInfo::Ref { .. } => "reference type",
}
.to_string()
}
Expand All @@ -1028,7 +1028,3 @@ fn recursively_depends_on(
.unwrap_or(false)
})
}

// -------------------------------------------------------------------------------------------------
//
//
16 changes: 12 additions & 4 deletions sway-core/src/semantic_analysis/type_check_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,10 @@ impl<'a> TypeCheckContext<'a> {
)));
}
}
TypeInfo::Ref(mut ty) => {
TypeInfo::Ref {
referenced_type: mut ty,
to_mutable_value,
} => {
ty.type_id = self
.resolve(
handler,
Expand All @@ -656,9 +659,14 @@ impl<'a> TypeCheckContext<'a> {
.insert(self.engines, TypeInfo::ErrorRecovery(err), None)
});

self.engines
.te()
.insert(self.engines, TypeInfo::Ref(ty.clone()), None)
self.engines.te().insert(
self.engines,
TypeInfo::Ref {
to_mutable_value,
referenced_type: ty.clone(),
},
None,
)
}
_ => type_id,
};
Expand Down
7 changes: 5 additions & 2 deletions sway-core/src/transform/to_parsed_lang/convert_parse_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1431,9 +1431,12 @@ fn ty_to_type_info(
let type_argument = ty_to_type_argument(context, handler, engines, *ty.into_inner())?;
TypeInfo::Slice(type_argument)
}
Ty::Ref { ty, .. } => {
Ty::Ref { mut_token, ty, .. } => {
let type_argument = ty_to_type_argument(context, handler, engines, *ty)?;
TypeInfo::Ref(type_argument)
TypeInfo::Ref {
to_mutable_value: mut_token.is_some(),
referenced_type: type_argument,
}
}
Ty::Never { .. } => TypeInfo::Never,
};
Expand Down
Loading

0 comments on commit f1c358d

Please sign in to comment.