Skip to content

Commit

Permalink
more sound impl for mutability on __slice and __elem_at
Browse files Browse the repository at this point in the history
  • Loading branch information
xunilrj committed Jul 31, 2024
1 parent 514ddf8 commit 77cd595
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 92 deletions.
39 changes: 19 additions & 20 deletions sway-core/src/ir_generation/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2181,30 +2181,29 @@ impl<'eng> FnCompiler<'eng> {

let first_argument_value = save_to_local_return_ptr(self, context, first_argument_value)?;

let ptr_arg = AsmArg {
name: Ident::new_no_span("ptr".into()),
initializer: Some(first_argument_value),
};

let ptr_out_arg = AsmArg {
name: Ident::new_no_span("ptr_out".into()),
initializer: Some(first_argument_value),
};

let return_type = Type::get_uint64(context);
let ptr_to_first_element = self.current_block.append(context).asm_block(
vec![ptr_arg, ptr_out_arg],
vec![AsmInstruction::lw_no_span("ptr_out", "ptr", "i0")],
return_type,
Some(Ident::new_no_span("ptr_out".into())),
);

match &*te.get(first_argument_expr.return_type) {
TypeInfo::Array(elem_ty, _) => Ok((first_argument_value, elem_ty.type_id)),
TypeInfo::Ref {
referenced_type, ..
} => match &*te.get(referenced_type.type_id) {
TypeInfo::Slice(elem_ty) => {
let ptr_arg = AsmArg {
name: Ident::new_no_span("ptr".into()),
initializer: Some(first_argument_value),
};

let ptr_out_arg = AsmArg {
name: Ident::new_no_span("ptr_out".into()),
initializer: Some(first_argument_value),
};

let return_type = Type::get_uint64(context);
let ptr_to_first_element = self.current_block.append(context).asm_block(
vec![ptr_arg, ptr_out_arg],
vec![AsmInstruction::lw_no_span("ptr_out", "ptr", "i0")],
return_type,
Some(Ident::new_no_span("ptr_out".into())),
);

TypeInfo::Array(elem_ty, _) | TypeInfo::Slice(elem_ty) => {
Ok((ptr_to_first_element, elem_ty.type_id))
}
_ => Err(err),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,22 +141,24 @@ fn type_check_elem_at(
ty::TyExpression::type_check(handler, ctx, &arguments[0])?
};

// first argument can be array or ref to slice
// first argument can be ref to array or ref to slice
let elem_type = match &*type_engine.get(first_argument_type) {
TypeInfo::Array(elem_ty, _) => Some(elem_ty.type_id),
TypeInfo::Ref {
referenced_type, ..
referenced_type,
to_mutable_value,
} => match &*type_engine.get(referenced_type.type_id) {
TypeInfo::Slice(elem_ty) => Some(elem_ty.type_id),
TypeInfo::Array(elem_ty, _) | TypeInfo::Slice(elem_ty) => {
Some((*to_mutable_value, elem_ty.type_id))
}
_ => None,
},
_ => None,
};
let Some(elem_type_type_id) = elem_type else {
let Some((to_mutable_value, elem_type_type_id)) = elem_type else {
return Err(handler.emit_err(CompileError::IntrinsicUnsupportedArgType {
name: kind.to_string(),
span: first_argument_span,
hint: "".to_string(),
hint: "Only references to arrays or slices can be used as argument here".to_string(),
}));
};

Expand All @@ -177,7 +179,7 @@ fn type_check_elem_at(
let return_type = type_engine.insert(
engines,
TypeInfo::Ref {
to_mutable_value: true,
to_mutable_value,
referenced_type: TypeArgument {
type_id: elem_type_type_id,
initial_type_id: elem_type_type_id,
Expand Down Expand Up @@ -280,12 +282,16 @@ fn type_check_slice(
}
}

fn create_ref_to_slice(engines: &Engines, elem_type_arg: TypeArgument) -> TypeId {
fn create_ref_to_slice(
engines: &Engines,
to_mutable_value: bool,
elem_type_arg: TypeArgument,
) -> TypeId {
let type_engine = engines.te();
let slice_type_id =
type_engine.insert(engines, TypeInfo::Slice(elem_type_arg.clone()), None);
let ref_to_slice_type = TypeInfo::Ref {
to_mutable_value: false,
to_mutable_value,
referenced_type: TypeArgument {
type_id: slice_type_id,
initial_type_id: slice_type_id,
Expand All @@ -296,57 +302,58 @@ fn type_check_slice(
type_engine.insert(engines, ref_to_slice_type, None)
}

// We can slice arrays or other slices
// first argument can be ref to array or ref to slice
let err = CompileError::IntrinsicUnsupportedArgType {
name: kind.to_string(),
span: first_argument_span,
hint: "".to_string(),
hint: "Only references to arrays or slices can be used as argument here".to_string(),
};
let r = match &*type_engine.get(first_argument_type) {
TypeInfo::Array(elem_type_arg, array_len) => {
let array_len = array_len.val() as u64;

if let Some(v) = start_literal {
if v > array_len {
return Err(handler.emit_err(CompileError::ArrayOutOfBounds {
index: v,
count: array_len,
span,
}));
TypeInfo::Ref {
referenced_type,
to_mutable_value,
} => match &*type_engine.get(referenced_type.type_id) {
TypeInfo::Array(elem_type_arg, array_len) => {
let array_len = array_len.val() as u64;

if let Some(v) = start_literal {
if v > array_len {
return Err(handler.emit_err(CompileError::ArrayOutOfBounds {
index: v,
count: array_len,
span,
}));
}
}
}

if let Some(v) = end_literal {
if v > array_len {
return Err(handler.emit_err(CompileError::ArrayOutOfBounds {
index: v,
count: array_len,
span,
}));
if let Some(v) = end_literal {
if v > array_len {
return Err(handler.emit_err(CompileError::ArrayOutOfBounds {
index: v,
count: array_len,
span,
}));
}
}
}

Some((
TyIntrinsicFunctionKind {
kind,
arguments: vec![first_argument_ty_expr, start_ty_expr, end_ty_expr],
type_arguments: vec![],
span,
},
create_ref_to_slice(engines, elem_type_arg.clone()),
))
}
TypeInfo::Ref {
referenced_type, ..
} => match &*type_engine.get(referenced_type.type_id) {
Some((
TyIntrinsicFunctionKind {
kind,
arguments: vec![first_argument_ty_expr, start_ty_expr, end_ty_expr],
type_arguments: vec![],
span,
},
create_ref_to_slice(engines, *to_mutable_value, elem_type_arg.clone()),
))
}
TypeInfo::Slice(elem_type_arg) => Some((
TyIntrinsicFunctionKind {
kind,
arguments: vec![first_argument_ty_expr, start_ty_expr, end_ty_expr],
type_arguments: vec![],
span,
},
create_ref_to_slice(engines, elem_type_arg.clone()),
create_ref_to_slice(engines, *to_mutable_value, elem_type_arg.clone()),
)),
_ => None,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,54 @@ script;

// slice cannot be consts
const GLOBAL_ARRAY: [u64; 5] = [1, 2, 3, 4, 5];
const GLOBAL_SLICE: &__slice[u64] = __slice(GLOBAL_ARRAY, 0, 5);
const GLOBAL_SLICE: &__slice[u64] = __slice(&GLOBAL_ARRAY, 0, 5);

fn main() {
type_check();

// slice cannot be consts
const LOCAL_ARRAY: [u64; 5] = [1, 2, 3, 4, 5];
const LOCAL_SLICE: &__slice[u64] = __slice(LOCAL_ARRAY, 0, 5);
const LOCAL_SLICE: &__slice[u64] = __slice(&LOCAL_ARRAY, 0, 5);

// Wrong start index
let a: [u64; 5] = [1, 2, 3, 4, 5];
let _ = __slice(a, 6, 7);
let _ = __slice(&a, 6, 7);

// Wrong end index
let a: [u64; 5] = [1, 2, 3, 4, 5];
let _ = __slice(a, 0, 6);
let _ = __slice(&a, 0, 6);

// Wrong first argument
__slice(0, 0, 0);

// Wrong start index
__slice(a, "", 0);
__slice(&a, "", 0);

// Wrong end index
__slice(a, 0, "");
__slice(&a, 0, "");

let a: [u64; 5] = [1, 2, 3, 4, 5];
let s: &__slice[u64] = __slice(LOCAL_ARRAY, 0, 5);
let s: &__slice[u64] = __slice(&LOCAL_ARRAY, 0, 5);

// Wrong first argument
__elem_at(0, 0);

// Wrong index type
__elem_at(a, "");
__elem_at(&a, "");

// Wrong index type
__elem_at(s, "");
}

fn type_check() {
// Cannot get mut ref from an immutable array
let immutable_array: [u64; 5] = [1, 2, 3, 4, 5];
let _: &mut u64 = __elem_at(&immutable_array, 0);

// Cannot get mut slice from an immutable array
let _: &mut __slice[u64] = __slice(&immutable_array, 0, 5);

// Cannot get mut ref from an immutable slice
let immutable_slice: &__slice[u64] = __slice(&immutable_array, 0, 5);
let _: &mut u64 = __elem_at(immutable_slice, 0);
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
category = "fail"

# check: let _ = __slice(a, 6, 7)
# check: __elem_at(&immutable_array, 0);
# nextln: $()Mismatched types.
# nextln: $()expected: &mut u64
# nextln: $()found: &u64

# check: __slice(&immutable_array, 0, 5);
# nextln: $()Mismatched types.
# nextln: $()expected: &mut __slice[u64]
# nextln: $()found: &__slice[u64]

# check: __elem_at(immutable_slice, 0);
# nextln: $()Mismatched types.
# nextln: $()expected: &mut u64
# nextln: $()found: &u64

# check: let _ = __slice(&a, 6, 7)
# nextln: $()Index out of bounds; the length is 5 but the index is 6.

# check: let _ = __slice(a, 0, 6)
# check: let _ = __slice(&a, 0, 6)
# nextln: $()Index out of bounds; the length is 5 but the index is 6.

# check: __slice(0, 0, 0)
# nextln: $()Unsupported argument type to intrinsic "slice"

# check: __slice(a, "", 0)
# check: __slice(&a, "", 0)
# nextln: $()Mismatched types
# nextln: $()expected: u64
# nextln: $()found: str

# check: __slice(a, 0, "")
# check: __slice(&a, 0, "")
# nextln: $()Mismatched types
# nextln: $()expected: u64
# nextln: $()found: str
#
# check: __elem_at(0, 0);
# nextln: $()Unsupported argument type to intrinsic "elem_at"

# check: __elem_at(a, "");
# check: __elem_at(&a, "");
# nextln: $()Mismatched types.
# nextln: $()expected: u64
# nextln: $()found: str.
Expand All @@ -32,8 +47,8 @@ category = "fail"
# nextln: $()expected: u64
# nextln: $()found: str.

# check: &__slice[u64] = __slice(GLOBAL_ARRAY, 0, 5)
# check: &__slice[u64] = __slice(&GLOBAL_ARRAY, 0, 5)
# nextln: $()slices or types containing slices on `const` are not allowed

# check: &__slice[u64] = __slice(LOCAL_ARRAY, 0, 5)
# check: &__slice[u64] = __slice(&LOCAL_ARRAY, 0, 5)
# nextln: $()slices or types containing slices on `const` are not allowed
Loading

0 comments on commit 77cd595

Please sign in to comment.