FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

lint: STYLE036 -- type contract that cannot act on a resolved cast type · feiyunwill/daScript@3a151c4 · GitHub

Commit 3a151c4

Browse files
andcommitted
lint: STYLE036 -- type contract that cannot act on a resolved cast type
-const / -& / -[] / -# / ==const / ==& are substitution contracts. They do work only while a generic binds, and infer clears them when it consumes them (ast_typedecl.cpp:223,422). A cast target that is already concrete has nothing to consume the contract, so a flag still set at lint time is proof it did nothing -- void? is void? regardless of -const. That "infer clears what it consumes" property is what makes the rule precise rather than heuristic: the generic case removes its own evidence. The one remaining exclusion is an auto or still-unresolved alias target, where substitution has not happened yet -- linq's reinterpret<ARGT -const> really does strip const from whatever ARGT binds, and skipping those took the daslib hit count from 179 to 5. Note a concrete typedef is NOT such a case: reinterpret<CI? -const> where CI = int const keeps the const, so the contract is inert there too and the rule correctly fires. Also fixes everything the three new rules found in daslib: - 5 x STYLE036, all dead -const on concrete reinterpret targets - 2 x LINT017, genuine 32-bit truncation in debug.das / debug_eval.das - 2 x STYLE030, `require strings` that existed only for length(str) and became unused when length moved to the base module Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 1144bf7 commit 3a151c4

9 files changed

Lines changed: 85 additions & 9 deletions

‎daslib/array_boost.das‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ def array_view(
248248
var res : array<TT -const>#
249249
if (length > 0) {
250250
let data = addr<TT -const?>(bytes[byte_offset])
251-
if (intptr(reinterpret<void? -const>(data)) % uint64(element_align) != 0_ul) {
251+
if (intptr(reinterpret<void?>(data)) % uint64(element_align) != 0_ul) {
252252
panic("array_view: unaligned typed view")
253253
}
254254
_builtin_make_temp_array(res, data, length)
@@ -262,7 +262,7 @@ def array_view(
262262
var res : array<TT -const>#
263263
if (length > 0_l) {
264264
let data = addr<TT -const?>(bytes[byte_offset])
265-
if (intptr(reinterpret<void? -const>(data)) % uint64(element_align) != 0_ul) {
265+
if (intptr(reinterpret<void?>(data)) % uint64(element_align) != 0_ul) {
266266
panic("array_view: unaligned typed view")
267267
}
268268
_builtin_make_temp_array_i64(res, data, length)

‎daslib/async_boost.das‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ module async_boost shared private
99
//! Provides ``[async]`` function annotation and ``await`` call macro that
1010
//! rewrite annotated functions into generator-based coroutines.
1111

12-
require strings
1312
require daslib/ast_boost
1413
require daslib/templates_boost
1514
require daslib/macro_boost

‎daslib/debug.das‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1303,7 +1303,7 @@ class private DAgent : DapiDebugAgent {
13031303
return
13041304
}
13051305
}
1306-
frame.state |> emplace <| (uid = STATE_VARS + uint64(length(frame.state)), name = category, vars = [ variable])
1306+
frame.state |> emplace <| (uid = STATE_VARS + uint64(long_length(frame.state)), name = category, vars = [ variable])
13071307
}
13081308
})
13091309
}

‎daslib/debug_eval.das‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ def func_call_length(var st : TokenStream; result : Result) : Result {
205205
}
206206
if (TypeInfo(basicType = Type.tString)) {
207207
let pstr = unsafe(reinterpret<string?>(getPD(st, result)))
208-
return <- Result(int64(length(*pstr)))
208+
return <- Result(long_length(*pstr))
209209
}
210210
if (TypeInfo(basicType = Type.tArray)) {
211211
let parr = unsafe(reinterpret<DapiArray?>(getPD(st, result)))

‎daslib/delegate.das‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ module delegate shared private
2222

2323
require daslib/macro_boost
2424
require daslib/typemacro_boost
25-
require strings
2625

2726
// ── helpers ────────────────────────────────────────────────────────────
2827

‎daslib/flatten_opt_common.das‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ def public subst_consts(var e : ExpressionPtr; constmap : table<string; Expressi
612612
var tmpl : Template
613613
for (nm in keys(constmap)) {
614614
// ?[] yields a const view; const-strip the raw pointer (apply_template clones per use anyway).
615-
var ex = unsafe(reinterpret<Expression? -const>(constmap?[nm] ?? null))
615+
var ex = unsafe(reinterpret<Expression?>(constmap?[nm] ?? null))
616616
tmpl |> replaceVariable(nm, ex)
617617
}
618618
var res = apply_template(tmpl, e.at, e, false)
@@ -718,7 +718,7 @@ def public store_base(e : Expression const?) : ExpressionPtr {
718718
if (e is ExprSwizzle) return store_base((e as ExprSwizzle).value)
719719
if (e is ExprPtr2Ref) return store_base((e as ExprPtr2Ref).subexpr)
720720
if (e is ExprRef2Value) return store_base((e as ExprRef2Value).subexpr)
721-
return e is ExprVar ? unsafe(reinterpret<Expression? -const>(e)) : null
721+
return e is ExprVar ? unsafe(reinterpret<Expression?>(e)) : null
722722
}
723723

724724
// Names reassigned somewhere in the block (live/loop masks `__flat_*`, any reassigned user `var`).

‎daslib/flatten_opt_preshade.das‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ def private regroup_to_share(var blk : ExprBlock?; no_fast_math : bool) : bool {
606606
def private alias_source(e : Expression const?) : ExpressionPtr {
607607
if (e == null) return null
608608
if (e is ExprRef2Value) return alias_source((e as ExprRef2Value).subexpr)
609-
return e is ExprVar ? unsafe(reinterpret<Expression? -const>(e)) : null
609+
return e is ExprVar ? unsafe(reinterpret<Expression?>(e)) : null
610610
}
611611

612612
def private eliminate_aliases(var blk : ExprBlock?) : bool {

‎daslib/style_lint.das‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2367,6 +2367,26 @@ class StyleLintVisitor : AstVisitor {
23672367
&& !expr.subexpr.genFlags.generated) {
23682368
style_warning("STYLE034: reinterpret<{describe(expr.castType)}>(addr(...)) collapses to addr<{describe(expr.castType)}>(...); one unsafe() covers both halves", expr.at)
23692369
}
2370+
// ===== STYLE036 — type contract that cannot act on a resolved cast type =====
2371+
if (!expr.genFlags.generated && expr.castType != null) {
2372+
let inert = style036_inert_contract(expr.castType)
2373+
if (!empty(inert)) {
2374+
let tail = inert == "-const" ? "; drop it, along with any 'const' it was meant to cancel" : "; drop it"
2375+
style_warning("STYLE036: '{inert}' does nothing on the already-resolved cast type {describe(expr.castType)}{tail}", expr.at)
2376+
}
2377+
}
2378+
}
2379+
2380+
def style036_inert_contract(t : TypeDecl?) : string {
2381+
// Substitution contracts: infer clears them when a generic binds (ast_typedecl.cpp:223,422), so one still set on a concrete target was never consumed — but an auto/unresolved-alias target has simply not been substituted yet (linq's `reinterpret<ARGT -const>` does strip const).
2382+
if (t.isAutoOrAlias) return ""
2383+
if (t.flags.removeConstant) return "-const"
2384+
if (t.flags.removeRef) return "-&"
2385+
if (t.flags.removeDim) return "-[]"
2386+
if (t.flags.removeTemporary) return "-#"
2387+
if (t.flags.explicitConst) return "==const"
2388+
if (t.flags.explicitRef) return "==&"
2389+
return ""
23702390
}
23712391

23722392
def override preVisitExprAt(expr : ExprAt?) : void {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
options gen2
2+
options auto_inline_functions = false // lint fixtures assert SOURCE shapes; splices rewrite them
3+
// STYLE036: type contract that cannot act on an already-resolved cast type
4+
//
5+
// Problem: -const / -& / -[] / -# / ==const / ==& are substitution contracts.
6+
// They do work only while a generic binds, and infer clears them once it
7+
// consumes them. A cast target is already concrete, so nothing ever consumes
8+
// the contract — void? is void? regardless of -const.
9+
//
10+
// Bad pattern:
11+
// let p = unsafe(addr<void? -const>(x))
12+
//
13+
// Good pattern:
14+
// let p = unsafe(addr<void?>(x))
15+
16+
typedef CI = int const
17+
18+
// bad: -const on an already-resolved pointer type (1 warning)
19+
def bad_remove_const(p : void?) : int? {
20+
return unsafe(reinterpret<int? -const>(p))
21+
}
22+
23+
// bad: -const through the addr<T?> sugar (1 warning)
24+
def bad_addr_sugar(var x : int) : void? {
25+
return unsafe(addr<void? -const>(x))
26+
}
27+
28+
// bad: -# on a type that is not temporary (1 warning)
29+
def bad_remove_temporary(p : void?) : int? {
30+
return unsafe(reinterpret<int? -#>(p))
31+
}
32+
33+
// bad: an alias is no different — the contract is inert there too (1 warning)
34+
def bad_alias_remove_const(p : void?) : CI? {
35+
return unsafe(reinterpret<CI? -const>(p))
36+
}
37+
38+
// good: no contract at all
39+
def good_plain(p : void?) : int? {
40+
return unsafe(reinterpret<int?>(p))
41+
}
42+
43+
// good: the sugar without a contract
44+
def good_addr_sugar(var x : int) : void? {
45+
return unsafe(addr<void?>(x))
46+
}
47+
48+
// good: a contract on a generic parameter is consumed by substitution, so it is
49+
// already cleared by the time any cast target is inspected
50+
def good_generic_contract(a : array<auto(TT)> -const) : int {
51+
return length(a)
52+
}
53+
54+
[export]
55+
def use_generic_contract() : int {
56+
var xs = [1, 2, 3]
57+
return good_generic_contract(xs)
58+
}

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL