sentinel pointers and c strings
This commit is contained in:
@@ -221,6 +221,19 @@ is_runtime_type :: proc(checker: ^Checker, value: types.Type) -> bool {
|
||||
return types.is_runtime_value(value, &checker.module.types)
|
||||
}
|
||||
|
||||
string_literal_type :: proc(checker: ^Checker, string_id: u64) -> types.Type {
|
||||
length: u64
|
||||
if string_id < u64(len(checker.ast_module.strings)) {
|
||||
length = u64(len(checker.ast_module.strings[string_id]))
|
||||
}
|
||||
array := types.array(&checker.module.types, types.U8, length, false, true, 0)
|
||||
return types.pointer(&checker.module.types, array, false, false)
|
||||
}
|
||||
|
||||
container_pointer_type :: proc(store: ^types.Store, item: types.Node) -> types.Type {
|
||||
return types.pointer(store, item.child, item.mutable, true, item.has_sentinel, item.sentinel)
|
||||
}
|
||||
|
||||
resolve_inferred_array :: proc(checker: ^Checker, value: types.Type, expr_id: ast.Expr_Id) -> types.Type {
|
||||
item, ok := types.node(&checker.module.types, value)
|
||||
if !ok || item.kind != .Array || !item.inferred_count ||
|
||||
@@ -665,7 +678,7 @@ validate_type_nodes :: proc(checker: ^Checker) {
|
||||
source.addf(
|
||||
checker.diagnostics,
|
||||
source.Span{},
|
||||
"sentinel value does not fit array or slice element type %s",
|
||||
"sentinel value does not fit array, slice, or pointer element type %s",
|
||||
types.name(item.child),
|
||||
)
|
||||
}
|
||||
@@ -809,7 +822,7 @@ infer_compound_expr :: proc(
|
||||
store := &checker.module.types
|
||||
#partial switch expr.kind {
|
||||
case .String:
|
||||
return types.slice(store, types.U8, false, true, 0)
|
||||
return string_literal_type(checker, expr.integer)
|
||||
case .Array:
|
||||
element := types.INVALID
|
||||
for arg in expr.args {
|
||||
@@ -835,11 +848,12 @@ infer_compound_expr :: proc(
|
||||
case .Index:
|
||||
value := infer_nested_expr(checker, expr.left, locals, pkg, file, demanded)
|
||||
_ = infer_nested_expr(checker, expr.right, locals, pkg, file, demanded)
|
||||
return types.child_type(value, store)
|
||||
item, ok := types.container(value, store)
|
||||
return item.child if ok else types.INVALID
|
||||
case .Slice:
|
||||
value := infer_nested_expr(checker, expr.left, locals, pkg, file, demanded)
|
||||
item, ok := types.node(store, value)
|
||||
if !ok || (item.kind != .Array && item.kind != .Slice) {
|
||||
item, ok := types.container(value, store)
|
||||
if !ok || item.kind == .Pointer {
|
||||
return types.INVALID
|
||||
}
|
||||
for bound in expr.args {
|
||||
@@ -851,14 +865,15 @@ infer_compound_expr :: proc(
|
||||
return types.slice(store, item.child, item.mutable, preserve, item.sentinel)
|
||||
case .Field:
|
||||
value := infer_nested_expr(checker, expr.left, locals, pkg, file, demanded)
|
||||
item, has_item := types.node(store, value)
|
||||
field_name := symbol_text(checker, expr.name)
|
||||
item, has_item := types.container(value, store)
|
||||
if has_item && (item.kind == .Array || item.kind == .Slice) {
|
||||
if field_name == "len" {
|
||||
return types.USIZE
|
||||
}
|
||||
if field_name == "ptr" {
|
||||
return types.pointer(store, item.child, item.mutable, true)
|
||||
if field_name == "ptr" &&
|
||||
(item.kind == .Slice || types.is_pointer(value, store)) {
|
||||
return container_pointer_type(store, item)
|
||||
}
|
||||
}
|
||||
if types.is_pointer(value, store) {
|
||||
@@ -950,13 +965,14 @@ infer_expr :: proc(
|
||||
last = find_infer_local(locals, expr.name)
|
||||
} else {
|
||||
base_type := find_infer_local(locals, expr.qualifier)
|
||||
item, has_item := types.node(&checker.module.types, base_type)
|
||||
item, has_item := types.container(base_type, &checker.module.types)
|
||||
field_name := symbol_text(checker, expr.name)
|
||||
if has_item && (item.kind == .Array || item.kind == .Slice) {
|
||||
if field_name == "len" {
|
||||
last = types.USIZE
|
||||
} else if field_name == "ptr" {
|
||||
last = types.pointer(&checker.module.types, item.child, item.mutable, true)
|
||||
} else if field_name == "ptr" &&
|
||||
(item.kind == .Slice || types.is_pointer(base_type, &checker.module.types)) {
|
||||
last = container_pointer_type(&checker.module.types, item)
|
||||
}
|
||||
}
|
||||
if types.is_pointer(base_type, &checker.module.types) {
|
||||
@@ -1296,11 +1312,35 @@ coerce_expr :: proc(
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
if types.can_weaken_slice(actual, expected, &checker.module.types) {
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.Weaken_Slice,
|
||||
span=span,
|
||||
type=expected,
|
||||
left=expr_id,
|
||||
target=hir.INVALID_REF,
|
||||
right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
if types.can_decay_array_pointer(actual, expected, &checker.module.types) {
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.Decay_Array_Pointer,
|
||||
span=span,
|
||||
type=expected,
|
||||
left=expr_id,
|
||||
target=hir.INVALID_REF,
|
||||
right=hir.INVALID_EXPR,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
if types.is_optional(expected, &checker.module.types) {
|
||||
child := types.child_type(expected, &checker.module.types)
|
||||
if types.equal(actual, child) ||
|
||||
types.can_widen(actual, child) ||
|
||||
types.can_weaken_pointer(actual, child, &checker.module.types) {
|
||||
types.can_weaken_pointer(actual, child, &checker.module.types) ||
|
||||
types.can_weaken_slice(actual, child, &checker.module.types) ||
|
||||
types.can_decay_array_pointer(actual, child, &checker.module.types) {
|
||||
value := coerce_expr(checker, expr_id, child, span)
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.Optional_Some,
|
||||
@@ -1475,7 +1515,8 @@ hir_location_writable :: proc(checker: ^Checker, expr_id: hir.Expr_Id, locals: [
|
||||
return types.is_mutable(pointer_type, &checker.module.types)
|
||||
case .Index:
|
||||
container_type := checker.module.exprs[expr.left].type
|
||||
return types.is_mutable(container_type, &checker.module.types)
|
||||
item, ok := types.container(container_type, &checker.module.types)
|
||||
return ok && item.mutable
|
||||
case .Field:
|
||||
base_type := checker.module.exprs[expr.left].type
|
||||
if types.is_pointer(base_type, &checker.module.types) {
|
||||
@@ -1539,7 +1580,7 @@ build_compound_expr :: proc(
|
||||
store := &checker.module.types
|
||||
#partial switch expr.kind {
|
||||
case .String:
|
||||
string_type := types.slice(store, types.U8, false, true, 0)
|
||||
string_type := string_literal_type(checker, expr.integer)
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.String, span=expr.span, type=string_type, integer=i64(expr.integer),
|
||||
target=hir.INVALID_REF, left=hir.INVALID_EXPR, right=hir.INVALID_EXPR,
|
||||
@@ -1639,9 +1680,9 @@ build_compound_expr :: proc(
|
||||
container := build_nested_expr(checker, expr.left, locals, global_reads, calls, types.INVALID, pkg, file)
|
||||
index := build_nested_expr(checker, expr.right, locals, global_reads, calls, types.USIZE, pkg, file)
|
||||
container_type := checker.module.exprs[container].type
|
||||
item, ok := types.node(store, container_type)
|
||||
if !ok || (item.kind != .Array && item.kind != .Slice && !(item.kind == .Pointer && item.many)) {
|
||||
id := source.add(checker.diagnostics, expr.span, "indexing requires an array, slice, or many-item pointer")
|
||||
item, ok := types.container(container_type, store)
|
||||
if !ok {
|
||||
id := source.add(checker.diagnostics, expr.span, "indexing requires an array, slice, pointer-to-array, or many-item pointer")
|
||||
return invalid_hir_expr(checker, expr.span, id)
|
||||
}
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
@@ -1651,9 +1692,9 @@ build_compound_expr :: proc(
|
||||
case .Slice:
|
||||
container := build_nested_expr(checker, expr.left, locals, global_reads, calls, types.INVALID, pkg, file)
|
||||
container_type := checker.module.exprs[container].type
|
||||
item, ok := types.node(store, container_type)
|
||||
if !ok || (item.kind != .Array && item.kind != .Slice) {
|
||||
id := source.add(checker.diagnostics, expr.span, "slicing requires an array or slice")
|
||||
item, ok := types.container(container_type, store)
|
||||
if !ok || item.kind == .Pointer {
|
||||
id := source.add(checker.diagnostics, expr.span, "slicing requires an array, slice, or pointer-to-array")
|
||||
return invalid_hir_expr(checker, expr.span, id)
|
||||
}
|
||||
bounds := make([]hir.Expr_Id, 2, checker.allocator)
|
||||
@@ -1673,8 +1714,8 @@ build_compound_expr :: proc(
|
||||
case .Field:
|
||||
base := build_nested_expr(checker, expr.left, locals, global_reads, calls, types.INVALID, pkg, file)
|
||||
base_type := checker.module.exprs[base].type
|
||||
item, has_item := types.node(store, base_type)
|
||||
field_name := symbol_text(checker, expr.name)
|
||||
item, has_item := types.container(base_type, store)
|
||||
if has_item && (item.kind == .Array || item.kind == .Slice) {
|
||||
if field_name == "len" {
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
@@ -1682,13 +1723,18 @@ build_compound_expr :: proc(
|
||||
target=hir.INVALID_REF, right=hir.INVALID_EXPR, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
if field_name == "ptr" {
|
||||
if field_name == "ptr" &&
|
||||
(item.kind == .Slice || types.is_pointer(base_type, store)) {
|
||||
return add_hir_expr(checker, hir.Expr{
|
||||
kind=.Slice_Ptr, span=expr.span,
|
||||
type=types.pointer(store, item.child, item.mutable, true), left=base,
|
||||
type=container_pointer_type(store, item), left=base,
|
||||
target=hir.INVALID_REF, right=hir.INVALID_EXPR, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
if field_name == "ptr" && item.kind == .Array {
|
||||
id := source.add(checker.diagnostics, expr.span, "arrays do not expose '.ptr'; take their address first")
|
||||
return invalid_hir_expr(checker, expr.span, id)
|
||||
}
|
||||
}
|
||||
if types.is_pointer(base_type, store) {
|
||||
base_type = types.child_type(base_type, store)
|
||||
@@ -1848,7 +1894,7 @@ build_expr :: proc(
|
||||
left=hir.INVALID_EXPR, right=hir.INVALID_EXPR, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
base_type := local.type
|
||||
item, has_item := types.node(&checker.module.types, base_type)
|
||||
item, has_item := types.container(base_type, &checker.module.types)
|
||||
field_name := symbol_text(checker, expr.name)
|
||||
if has_item && (item.kind == .Array || item.kind == .Slice) {
|
||||
if field_name == "len" {
|
||||
@@ -1856,12 +1902,16 @@ build_expr :: proc(
|
||||
kind=.Length, span=expr.span, type=types.USIZE, left=base,
|
||||
target=hir.INVALID_REF, right=hir.INVALID_EXPR, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
} else if field_name == "ptr" {
|
||||
} else if field_name == "ptr" &&
|
||||
(item.kind == .Slice || types.is_pointer(base_type, &checker.module.types)) {
|
||||
last = add_hir_expr(checker, hir.Expr{
|
||||
kind=.Slice_Ptr, span=expr.span,
|
||||
type=types.pointer(&checker.module.types, item.child, item.mutable, true), left=base,
|
||||
type=container_pointer_type(&checker.module.types, item), left=base,
|
||||
target=hir.INVALID_REF, right=hir.INVALID_EXPR, diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
} else if field_name == "ptr" && item.kind == .Array {
|
||||
id := source.add(checker.diagnostics, expr.span, "arrays do not expose '.ptr'; take their address first")
|
||||
last = invalid_hir_expr(checker, expr.span, id)
|
||||
}
|
||||
}
|
||||
if types.is_pointer(base_type, &checker.module.types) {
|
||||
|
||||
Reference in New Issue
Block a user