Extract `computeUnionLayout` and `variantTag`
dd43ff042198173faf31c570a1dd532fe9d9789168a1e0438c7e7492cd3b60f3
Extract union layout computation and variant discriminant tag logic into standalone functions. This is a pure refactoring with no behavior change, preparing for reuse in generic union instantiation.
1 parent
7c8cce71
lib/std/lang/resolver.rad
+51 -32
| 154 | 154 | size: u32, |
|
| 155 | 155 | /// Alignment in bytes. |
|
| 156 | 156 | alignment: u32, |
|
| 157 | 157 | } |
|
| 158 | 158 | ||
| 159 | + | /// Computed union layout parameters. |
|
| 160 | + | record UnionLayoutInfo { |
|
| 161 | + | layout: Layout, |
|
| 162 | + | valOffset: u32, |
|
| 163 | + | isAllVoid: bool, |
|
| 164 | + | } |
|
| 165 | + | ||
| 159 | 166 | /// Pre-computed metadata for slice range expressions. |
|
| 160 | 167 | /// Used by the lowerer. |
|
| 161 | 168 | pub record SliceRangeInfo { |
|
| 162 | 169 | /// Element type of the resulting slice. |
|
| 163 | 170 | itemType: *Type, |
| 1381 | 1388 | size: PTR_SIZE + maxSize, |
|
| 1382 | 1389 | alignment: max(PTR_SIZE, maxAlign), |
|
| 1383 | 1390 | }; |
|
| 1384 | 1391 | } |
|
| 1385 | 1392 | ||
| 1393 | + | /// Compute the layout for a union given its resolved variants. |
|
| 1394 | + | fn computeUnionLayout(variants: *[UnionVariant]) -> UnionLayoutInfo { |
|
| 1395 | + | let tagSize: u32 = 1; |
|
| 1396 | + | let mut maxVarSize: u32 = 0; |
|
| 1397 | + | let mut maxVarAlign: u32 = 1; |
|
| 1398 | + | let mut isAllVoid: bool = true; |
|
| 1399 | + | ||
| 1400 | + | for i in 0..variants.len { |
|
| 1401 | + | let payloadType = variants[i].valueType; |
|
| 1402 | + | if payloadType != Type::Void { |
|
| 1403 | + | isAllVoid = false; |
|
| 1404 | + | let payloadLayout = getTypeLayout(payloadType); |
|
| 1405 | + | maxVarSize = max(maxVarSize, payloadLayout.size); |
|
| 1406 | + | maxVarAlign = max(maxVarAlign, payloadLayout.alignment); |
|
| 1407 | + | } |
|
| 1408 | + | } |
|
| 1409 | + | let unionAlignment: u32 = max(1, maxVarAlign); |
|
| 1410 | + | let unionValOffset: u32 = mem::alignUp(tagSize, maxVarAlign); |
|
| 1411 | + | let unionLayout = Layout { |
|
| 1412 | + | size: mem::alignUp(unionValOffset + maxVarSize, unionAlignment), |
|
| 1413 | + | alignment: unionAlignment, |
|
| 1414 | + | }; |
|
| 1415 | + | return UnionLayoutInfo { layout: unionLayout, valOffset: unionValOffset, isAllVoid }; |
|
| 1416 | + | } |
|
| 1417 | + | ||
| 1418 | + | /// Compute the discriminant tag for a variant, advancing the iota counter. |
|
| 1419 | + | /// If the variant has an explicit `= N` value, uses that; otherwise uses iota. |
|
| 1420 | + | fn variantTag(variantDecl: ast::UnionDeclVariant, iota: *mut u32) -> u32 { |
|
| 1421 | + | let mut tag: u32 = *iota; |
|
| 1422 | + | if let valueNode = variantDecl.value { |
|
| 1423 | + | let case ast::NodeValue::Number(lit) = valueNode.value |
|
| 1424 | + | else panic "variantTag: expected number literal"; |
|
| 1425 | + | tag = lit.magnitude as u32; |
|
| 1426 | + | } |
|
| 1427 | + | *iota = tag + 1; |
|
| 1428 | + | return tag; |
|
| 1429 | + | } |
|
| 1430 | + | ||
| 1386 | 1431 | /// Check if a type is a union without payloads. |
|
| 1387 | 1432 | pub fn isVoidUnion(ty: Type) -> bool { |
|
| 1388 | 1433 | let case Type::Nominal(info) = ty |
|
| 1389 | 1434 | else return false; |
|
| 1390 | 1435 | let case NominalType::Union(unionType) = *info |
| 3139 | 3184 | if let ty = try visitOptional(self, variantDecl.type, Type::Unknown) { |
|
| 3140 | 3185 | variantType = ty; |
|
| 3141 | 3186 | } |
|
| 3142 | 3187 | // Process the variant's explicit discriminant value if present. |
|
| 3143 | 3188 | try visitOptional(self, variantDecl.value, variantType); |
|
| 3144 | - | let mut variantTag: u32 = iota; |
|
| 3145 | - | if let valueNode = variantDecl.value { |
|
| 3146 | - | let case ast::NodeValue::Number(lit) = valueNode.value |
|
| 3147 | - | else panic "resolveUnionBody: expected number literal for variant value"; |
|
| 3148 | - | variantTag = lit.magnitude as u32; |
|
| 3149 | - | } |
|
| 3150 | - | iota = variantTag + 1; |
|
| 3189 | + | let tag = variantTag(variantDecl, &mut iota); |
|
| 3151 | 3190 | // Create a symbol for this variant. |
|
| 3152 | - | let data = SymbolData::Variant { type: variantType, decl: node, ordinal: i, index: variantTag }; |
|
| 3191 | + | let data = SymbolData::Variant { type: variantType, decl: node, ordinal: i, index: tag }; |
|
| 3153 | 3192 | let variantSym = allocSymbol(self, data, variantName, variantNode, 0); |
|
| 3154 | 3193 | ||
| 3155 | 3194 | variants[variantCount] = UnionVariant { |
|
| 3156 | 3195 | name: variantName, |
|
| 3157 | 3196 | valueType: variantType, |
|
| 3158 | 3197 | symbol: variantSym, |
|
| 3159 | 3198 | }; |
|
| 3160 | 3199 | variantCount += 1; |
|
| 3161 | 3200 | } |
|
| 3162 | - | // Compute cached layout values. |
|
| 3163 | - | let tagSize: u32 = 1; |
|
| 3164 | - | let mut maxVarSize: u32 = 0; |
|
| 3165 | - | let mut maxVarAlign: u32 = 1; |
|
| 3166 | - | let mut isAllVoid: bool = true; |
|
| 3167 | - | ||
| 3168 | - | for i in 0..variantCount { |
|
| 3169 | - | let payloadType = variants[i].valueType; |
|
| 3170 | - | if payloadType != Type::Void { |
|
| 3171 | - | isAllVoid = false; |
|
| 3172 | - | let payloadLayout = getTypeLayout(payloadType); |
|
| 3173 | - | maxVarSize = max(maxVarSize, payloadLayout.size); |
|
| 3174 | - | maxVarAlign = max(maxVarAlign, payloadLayout.alignment); |
|
| 3175 | - | } |
|
| 3176 | - | } |
|
| 3177 | - | let unionAlignment: u32 = max(1, maxVarAlign); |
|
| 3178 | - | let unionValOffset: u32 = mem::alignUp(tagSize, maxVarAlign); |
|
| 3179 | - | let unionLayout = Layout { |
|
| 3180 | - | size: mem::alignUp(unionValOffset + maxVarSize, unionAlignment), |
|
| 3181 | - | alignment: unionAlignment |
|
| 3182 | - | }; |
|
| 3201 | + | let info = computeUnionLayout(&variants[..variantCount]); |
|
| 3183 | 3202 | ||
| 3184 | 3203 | // Update the nominal type with the resolved variants. |
|
| 3185 | 3204 | *nominalTy = NominalType::Union(UnionType { |
|
| 3186 | 3205 | variants, |
|
| 3187 | 3206 | variantsLen: variantCount, |
|
| 3188 | - | layout: unionLayout, |
|
| 3189 | - | valOffset: unionValOffset, |
|
| 3190 | - | isAllVoid, |
|
| 3207 | + | layout: info.layout, |
|
| 3208 | + | valOffset: info.valOffset, |
|
| 3209 | + | isAllVoid: info.isAllVoid, |
|
| 3191 | 3210 | }); |
|
| 3192 | 3211 | } |
|
| 3193 | 3212 | ||
| 3194 | 3213 | /// Check if a module should be analyzed based on its attributes and build configuration. |
|
| 3195 | 3214 | fn shouldAnalyzeModule(self: *Resolver, attrs: ?ast::Attributes) -> bool { |