lang: allow copy_from_slice arg to be read-only
diff --git a/lang/builtin/builtin.go b/lang/builtin/builtin.go
index 88febcf..25e08e2 100644
--- a/lang/builtin/builtin.go
+++ b/lang/builtin/builtin.go
@@ -912,16 +912,20 @@
// "table T" types. After tokenizing (but before parsing) these XxxFunc strings
// (e.g. in the lang/check package), replace "T1" and "T2" with "†" or "‡"
// daggers, to avoid collision with a user-defined "T1" or "T2" type.
+//
+// Ditto for "R1" / "ρ", for a read-only flavor of "T1" / "†".
const (
- genericOldName1 = t.IDT1
- genericOldName2 = t.IDT2
- genericNewName1 = t.IDDagger1
- genericNewName2 = t.IDDagger2
+ genericOldName1 = t.IDT1
+ genericOldName2 = t.IDT2
+ genericOldNameRo1 = t.IDR1
+ genericNewName1 = t.IDDagger1
+ genericNewName2 = t.IDDagger2
+ genericNewNameRo1 = t.IDRho1
)
var SliceFuncs = []string{
- "GENERIC T1.copy_from_slice!(s: T1) u64",
+ "GENERIC T1.copy_from_slice!(s: R1) u64",
"GENERIC T1.length() u64",
"GENERIC T1.prefix(up_to: u64) T1",
"GENERIC T1.uintptr_low_12_bits() u32[..= 4095]",
@@ -997,10 +1001,13 @@
if generic {
for i := range tokens {
- if id := tokens[i].ID; id == genericOldName1 {
- tokens[i].ID = genericNewName1
+ tok := &tokens[i]
+ if id := tok.ID; id == genericOldName1 {
+ tok.ID = genericNewName1
} else if id == genericOldName2 {
- tokens[i].ID = genericNewName2
+ tok.ID = genericNewName2
+ } else if id == genericOldNameRo1 {
+ tok.ID = genericNewNameRo1
}
}
}
diff --git a/lang/check/resolve.go b/lang/check/resolve.go
index 70ca2ae..4d9ade9 100644
--- a/lang/check/resolve.go
+++ b/lang/check/resolve.go
@@ -32,6 +32,7 @@
var (
typeExprGeneric1 = a.NewTypeExpr(0, t.IDBase, t.IDDagger1, nil, nil, nil)
typeExprGeneric2 = a.NewTypeExpr(0, t.IDBase, t.IDDagger2, nil, nil, nil)
+ typeExprGenericRo1 = a.NewTypeExpr(0, t.IDBase, t.IDRho1, nil, nil, nil)
typeExprIdeal = a.NewTypeExpr(0, t.IDBase, t.IDQIdeal, nil, nil, nil)
typeExprList = a.NewTypeExpr(0, t.IDBase, t.IDComma, nil, nil, nil)
typeExprNonNullptr = a.NewTypeExpr(0, t.IDBase, t.IDQNonNullptr, nil, nil, nil)
diff --git a/lang/check/type.go b/lang/check/type.go
index 9b9e0b7..07eb7a3 100644
--- a/lang/check/type.go
+++ b/lang/check/type.go
@@ -624,16 +624,24 @@
genericType1 := (*a.TypeExpr)(nil)
genericType2 := (*a.TypeExpr)(nil)
+ genericTypeRo1 := (*a.TypeExpr)(nil)
if recv := f.Receiver(); recv[0] == t.IDBase {
switch recv[1] {
case t.IDDagger1:
+ decorator := t.ID(0)
genericType1 = lhs.MType().Receiver()
+ if gt1Dec := genericType1.Decorator(); (gt1Dec == t.IDRoslice) || (gt1Dec == t.IDSlice) {
+ decorator = t.IDRoslice
+ } else {
+ return fmt.Errorf("check: internal error: %q is not a generic slice", genericType1.Str(q.tm))
+ }
+ genericTypeRo1 = a.NewTypeExpr(decorator, 0, 0, nil, nil, genericType1.Inner())
case t.IDDagger2:
decorator := t.ID(0)
genericType2 = lhs.MType().Receiver()
- if genericType2.Decorator() == t.IDRotable {
+ if gt2Dec := genericType2.Decorator(); gt2Dec == t.IDRotable {
decorator = t.IDRoslice
- } else if genericType2.Decorator() == t.IDTable {
+ } else if gt2Dec == t.IDTable {
decorator = t.IDSlice
} else {
return fmt.Errorf("check: internal error: %q is not a generic table", genericType2.Str(q.tm))
@@ -664,6 +672,8 @@
inFieldTyp = genericType1
} else if genericType2 != nil && inFieldTyp.Eq(typeExprGeneric2) {
inFieldTyp = genericType2
+ } else if genericTypeRo1 != nil && inFieldTyp.Eq(typeExprGenericRo1) {
+ inFieldTyp = genericTypeRo1
}
if err := q.tcheckEq(inField.Name(), nil, inFieldTyp, o.Value(), o.Value().MType()); err != nil {
return err
@@ -1149,7 +1159,8 @@
// TODO: reject. You can only refine numeric types.
}
if qid[0] == t.IDBase {
- if _, ok := builtInTypeMap[qid[1]]; ok || qid[1] == t.IDDagger1 || qid[1] == t.IDDagger2 {
+ if _, ok := builtInTypeMap[qid[1]]; ok ||
+ qid[1] == t.IDDagger1 || qid[1] == t.IDDagger2 || qid[1] == t.IDRho1 {
break swtch
}
}
diff --git a/lang/token/list.go b/lang/token/list.go
index 2ace176..dc45b72 100644
--- a/lang/token/list.go
+++ b/lang/token/list.go
@@ -439,10 +439,12 @@
IDCoroutineResumed = ID(0x101)
IDThis = ID(0x102)
- IDT1 = ID(0x104)
- IDT2 = ID(0x105)
- IDDagger1 = ID(0x106)
- IDDagger2 = ID(0x107)
+ IDR1 = ID(0x104)
+ IDT1 = ID(0x105)
+ IDT2 = ID(0x106)
+ IDRho1 = ID(0x107)
+ IDDagger1 = ID(0x108)
+ IDDagger2 = ID(0x109)
IDQNonNullptr = ID(0x10A)
IDQNullptr = ID(0x10B)
@@ -851,10 +853,13 @@
// specifically non-ASCII so that no user-defined (non built-in) identifier
// will conflict with them.
- // IDDaggerN is used by the type checker as a placeholder built-in ID to
- // represent a generic type.
+ // IDRhoN and IDDaggerN are used by the type checker as placeholder
+ // built-in IDs to represent generic 1-dimensional (slice) or 2-dimensional
+ // (table) types. The Rho flavor is read-only.
+ IDR1: "R1",
IDT1: "T1",
IDT2: "T2",
+ IDRho1: "ρ", // U+03C1 GREEK SMALL LETTER RHO
IDDagger1: "†", // U+2020 DAGGER
IDDagger2: "‡", // U+2021 DOUBLE DAGGER