You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
self.p / 2 on an int auto-property returns 3.5 in Python and JS, and self.p + 1L fails to compile in Rust: property reads have no static type #466
#433 made a member read such as self.total carry its field's declared type, so integer arithmetic on it is lowered correctly. The lookup behind that fix does not consider properties:
DeclaredFieldType (Coder/Languages/StandardLanguageGenerator.cs:625-650, reached through DottedMemberType at :574) matches only FieldDeclaration and VariableDeclaration members of the class.
DeclaredMemberType (:807-830) has the same gap.
An automatic PropertyDeclaration is lowered to a plain field in every target. Separated rewrites it only in the member list it writes out, while these lookups read the original classDecl.Members, where the member is still a PropertyDeclaration. Its reads therefore have no known type, and every StaticType-driven lowering is skipped for them.
class Acc has three int members: a FieldDeclaration f, an automatic PropertyDeclaration p (HasSetter = true, no accessor bodies) and a VariableDeclaration v. Each has a method int half_X() returning BinaryExpression(VariableReference("self.X"), Divide, Literal<int>(2)), written this.X for JS.
Target
f and v
p
Python
self.f // 2 if ... else -(-self.f // 2), so 7 gives 3
return (self.p / 2), so 7 gives 3.5 (executed)
JavaScript
Math.trunc((this.f / 2)), so 7 gives 3
return (this.p / 2), so 7 gives 3.5 (executed)
Rust, long wide_X() => self.X + 1L
(self.f as i64) + 1, which compiles
(self.p + 1): rustc E0308 mismatched types, i32 vs i64
% on p is also wrong in Python, which floors it.
Why it matters
An AST that declares state as an automatic property, which is the normal C# shape, gets silently wrong arithmetic in Python and JS and a compile error in Rust. The same AST with a field is correct. That is exactly the class of bug #433 closed, still open for properties.
Suggested fix
In DeclaredFieldType and DeclaredMemberType, also match PropertyDeclaration members by Name and use their Type, at least for automatic properties. A property with accessor bodies is still read through its getter, whose return type is the same.
Priority: High. This is silent miscompilation. In Python and JS an int automatic property divided by 2 gives 3.5 where a field gives 3, and nothing fails at generation or run time. The usual C# way of declaring state (an automatic property) is enough to trigger it. Rust only gets a compile error, which is at least visible.
Activity
matt-edmondson commentedon Nov 7, 2026
Triage
intautomatic property divided by 2 gives3.5where a field gives3, and nothing fails at generation or run time. The usual C# way of declaring state (an automatic property) is enough to trigger it. Rust only gets a compile error, which is at least visible.StandardLanguageGenerator.DeclaredFieldType(:625-650) andDeclaredMemberType(:807-830), the static-type lookup added by Integer/and%on an instance field (self.total / 2,p.total % 2) use Python/JS native division: an int-typed method returns -3.5 instead of -3 #433. Owner: @matt-edmondsonvoid* b = (-a);, Go types-(1.5f)as float64, and Python/JS do true division on-a / 2#267 (a unary expression loses its static type) and the closed Integer/and%on an instance field (self.total / 2,p.total % 2) use Python/JS native division: an int-typed method returns -3.5 instead of -3 #433, and Rust: a record holding a struct through an auto-property fails to compile (E0277), because the held struct never derives Clone/Debug/PartialEq #353 also involves auto-properties. No open PR changes these lookups: Type a shift as its left operand [patch] #460 (shift typing) and Say an inferred member's type in C# and C++ instead of var/auto [patch] #454 (inferred member types) are nearby but different.PropertyDeclarationbyNamein both lookups and use itsType. Add the Python/and%, JS/and Rust widening tests next to Integer/and%on an instance field (self.total / 2,p.total % 2) use Python/JS native division: an int-typed method returns -3.5 instead of -3 #433's.Generated by Claude Code