feat(lsp): parse own/parenthesized/nullable types and report implicit conversions
ParseType now understands `own T`, `(T)` and `T?`, so assignment checks reuse the existing int/pointer conversion codes (integer<->pointer, pointer mismatch). Value-typed targets reject pointer values, and duplicate nullable reporting is gone.
This commit is contained in:
1 parent
295d78aa56
commit
2c65cea97f
2 files changed
+36
-7
No files matched your search
@@ -1570,14 +1570,16 @@ def _WalkChecks(pool: memhub.MemManager*, doc: LspDocuments.LspDocument*,
|
||||
ann: str = _DeclAnnotationText(pool, doc, an.target)
|
||||
dst: LspTypes.LspType* = LspTypes.ParseType(pool, ann)
|
||||
_CheckAssignValue(pool, doc, a, ws, table_pool, dst, an.value, None, errors)
|
||||
if _NullableDetail(ann) == 0 \
|
||||
if an.value is not None and _AnnIsPointerLike(pool, doc, an) != 0 \
|
||||
and _NullableDetail(ann) == 0 \
|
||||
and _NullableDetail(_SymDetailAt(pool, a, an.value)) != 0:
|
||||
_EmitTypeError(pool, doc, an.value,
|
||||
"a nullable value may be None; declare the target as `T?` or unwrap it with `match` first", errors)
|
||||
_WalkChecksExprs(pool, doc, a, ws, table_pool, an.value, errors)
|
||||
if an.value is not None and _AnnIsPointerLike(pool, doc, an) == 0 \
|
||||
and _NullableDetail(_SymDetailAt(pool, a, an.value)) == 0 \
|
||||
and _ValueIsPointer(pool, a, an.value) != 0:
|
||||
and _ValueIsPointer(pool, a, an.value) != 0 \
|
||||
and (an.value.kind() == ast.ASTKind.New or dst is None
|
||||
or dst.kind == LspTypes.LT_AGG or dst.kind == LspTypes.LT_UNKNOWN):
|
||||
_EmitTypeError(pool, doc, an.value,
|
||||
"a pointer/`own` value cannot be stored into a value-typed variable; declare the target as `own T` / `T*`, or dereference explicitly (`*p`)", errors)
|
||||
if an.target is not None and an.target.kind() == ast.ASTKind.Name:
|
||||
@@ -1604,15 +1606,17 @@ def _WalkChecks(pool: memhub.MemManager*, doc: LspDocuments.LspDocument*,
|
||||
continue
|
||||
dst_t: LspTypes.LspType* = _TypeFromDetail(pool, tt.detail)
|
||||
_CheckAssignValue(pool, doc, a, ws, table_pool, dst_t, asn.value, None, errors)
|
||||
if _NullableDetail(tt.detail) == 0 \
|
||||
if _DetailIsPointer(tt.detail) != 0 and _NullableDetail(tt.detail) == 0 \
|
||||
and _NullableDetail(_SymDetailAt(pool, a, asn.value)) != 0:
|
||||
_EmitTypeError(pool, doc, asn.value,
|
||||
"a nullable value may be None; declare the target as `T?` or unwrap it with `match` first", errors)
|
||||
if tt.detail is not None and _DetailIsPointer(tt.detail) == 0 \
|
||||
and _NullableDetail(_SymDetailAt(pool, a, asn.value)) == 0 \
|
||||
and _ValueIsPointer(pool, a, asn.value) != 0:
|
||||
_EmitTypeError(pool, doc, asn.value,
|
||||
"a pointer/`own` value cannot be stored into a value-typed variable; declare the target as `own T` / `T*`, or dereference explicitly (`*p`)", errors)
|
||||
dst_a: LspTypes.LspType* = _TypeFromDetail(pool, tt.detail)
|
||||
if asn.value.kind() == ast.ASTKind.New or dst_a is None \
|
||||
or dst_a.kind == LspTypes.LT_AGG or dst_a.kind == LspTypes.LT_UNKNOWN:
|
||||
_EmitTypeError(pool, doc, asn.value,
|
||||
"a pointer/`own` value cannot be stored into a value-typed variable; declare the target as `own T` / `T*`, or dereference explicitly (`*p`)", errors)
|
||||
_WalkChecksExprs(pool, doc, a, ws, table_pool, asn.value, errors)
|
||||
if asn.value is not None and asn.value.kind() == ast.ASTKind.Name:
|
||||
sn_a: ast.Name* = ast.Name*(asn.value)
|
||||
|
||||
@@ -243,6 +243,31 @@ def ParseType(pool: memhub.MemManager*, text: str) -> LspType*:
|
||||
if p is not None:
|
||||
p.pointee = inner
|
||||
return p
|
||||
# Parenthesized type group: `( T )` (suffixes such as `?` are handled below/outside).
|
||||
w_len0: sizet = string.strlen(working)
|
||||
if w_len0 >= 2 and working[0] == '(' and working[w_len0 - 1] == ')':
|
||||
return ParseType(pool, _Trim(pool, _Slice(pool, working, 1, int(w_len0 - 1))))
|
||||
# Ownership prefix: `own T` (one owned pointer layer; an existing pointer keeps its layer).
|
||||
if _Starts(working, "own ") != 0:
|
||||
rest_own: str = _Trim(pool, _Slice(pool, working, 4, int(string.strlen(working))))
|
||||
inner_own: LspType* = ParseType(pool, rest_own)
|
||||
if inner_own is not None and inner_own.kind == LT_PTR:
|
||||
return inner_own
|
||||
p_own: LspType* = _NewType(pool, LT_PTR)
|
||||
if p_own is not None:
|
||||
p_own.pointee = inner_own
|
||||
return p_own
|
||||
# Nullable suffix: `T?` (pointer niche; an existing pointer keeps its layer).
|
||||
n_q: sizet = string.strlen(working)
|
||||
if n_q > 0 and working[n_q - 1] == '?':
|
||||
base_q: str = _Trim(pool, _Slice(pool, working, 0, int(n_q - 1)))
|
||||
inner_q: LspType* = ParseType(pool, base_q)
|
||||
if inner_q is not None and inner_q.kind == LT_PTR:
|
||||
return inner_q
|
||||
p_q: LspType* = _NewType(pool, LT_PTR)
|
||||
if p_q is not None:
|
||||
p_q.pointee = inner_q
|
||||
return p_q
|
||||
# Leading array: []T / [N]T.
|
||||
if string.strlen(working) > 0 and working[0] == '[':
|
||||
close: int = -1
|
||||
|
||||
Reference in new issue
Block a user