compiler: Retain immutable standalone method metadata
6895879fcbdd55844fb71b504781410e22ce59c567f401cd68fa8226a254f269
1 parent
84c0637c
lib/std/lang/lower.rad
+2 -3
| 1284 | 1284 | ) -> ?*unsafe il::Fn throws (LowerError) where 'arena: 'phase { |
|
| 1285 | 1285 | let sym = resolver::symbolFor(self.resolver, node) |
|
| 1286 | 1286 | else throw LowerError::MissingSymbol(node); |
|
| 1287 | 1287 | let case ast::NodeValue::Ident(mName) = name.value |
|
| 1288 | 1288 | else throw LowerError::ExpectedIdentifier; |
|
| 1289 | - | let me = resolver::findMethodBySymbol(self.resolver, sym) |
|
| 1289 | + | let me = resolver::findMethodBySymbol(self.resolver, sym.id) |
|
| 1290 | 1290 | else throw LowerError::MissingMetadata; |
|
| 1291 | 1291 | let qualName = instanceMethodName(self, nil, me.concreteTypeName, mName); |
|
| 1292 | 1292 | ||
| 1293 | 1293 | return try lowerMethod(self, node, qualName, receiverName, sig, body, functionArena); |
|
| 1294 | 1294 | } |
| 7171 | 7171 | // Get the receiver as a pointer. |
|
| 7172 | 7172 | let parentTy = try typeOf(self, access.parent); |
|
| 7173 | 7173 | let receiverVal = try lowerReceiver(self, access.parent, parentTy); |
|
| 7174 | 7174 | ||
| 7175 | 7175 | let qualName = instanceMethodName(self.low, nil, method.concreteTypeName, method.name); |
|
| 7176 | - | let case resolver::SymbolData::Value { type: resolver::Type::Fn(fnInfo), .. } = method.symbol.data |
|
| 7177 | - | else panic "lowerMethodCall: expected Fn type on method symbol"; |
|
| 7176 | + | let fnInfo = method.fullFnType; |
|
| 7178 | 7177 | ||
| 7179 | 7178 | // Build args: optional return param slot + receiver + user args. |
|
| 7180 | 7179 | let argOffset: u32 = 1 if requiresReturnParam(fnInfo) else 0; |
|
| 7181 | 7180 | let args = try allocVals(self, call.args.len + 1 + argOffset); |
|
| 7182 | 7181 | set args[argOffset] = receiverVal; |
lib/std/lang/resolver.rad
+12 -8
| 108 | 108 | fnType: *FnType, |
|
| 109 | 109 | /// Whether the receiver is mutable. |
|
| 110 | 110 | mutable: bool, |
|
| 111 | 111 | /// Pointer-like class used by the receiver. |
|
| 112 | 112 | receiverClass: types::PointerClass, |
|
| 113 | - | /// Symbol for the method. |
|
| 114 | - | symbol: *unsafe mut Symbol, |
|
| 113 | + | /// Resolver-local identity of the method symbol. |
|
| 114 | + | symbolId: u32, |
|
| 115 | + | /// Function type including the receiver, used for emitted calls. |
|
| 116 | + | fullFnType: *FnType, |
|
| 115 | 117 | } |
|
| 116 | 118 | ||
| 117 | 119 | /// Identifier for the synthetic `len` field. |
|
| 118 | 120 | export constant LEN_FIELD: *[u8] = "len"; |
|
| 119 | 121 | /// Identifier for the synthetic `ptr` field. |
| 5484 | 5486 | paramTypes: ¶mTypes[..], |
|
| 5485 | 5487 | returnType: retTypePtr, |
|
| 5486 | 5488 | throwList, |
|
| 5487 | 5489 | isUnsafe, |
|
| 5488 | 5490 | }; |
|
| 5489 | - | let fnTy = Type::Fn(allocFnType(self, fullFnType)); |
|
| 5491 | + | let fullFnInfo = allocFnType(self, fullFnType); |
|
| 5492 | + | let fnTy = Type::Fn(fullFnInfo); |
|
| 5490 | 5493 | ||
| 5491 | 5494 | // Function type excluding receiver, for call arg checking. |
|
| 5492 | 5495 | let checkFnType = FnType { |
|
| 5493 | 5496 | regions: self.regionScope, |
|
| 5494 | 5497 | paramTypes: ¶mTypes[1..], |
| 5515 | 5518 | concreteTypeName: typeName, |
|
| 5516 | 5519 | name: methodName, |
|
| 5517 | 5520 | fnType: allocFnType(self, checkFnType), |
|
| 5518 | 5521 | mutable: receiverMut, |
|
| 5519 | 5522 | receiverClass, |
|
| 5520 | - | symbol: sym, |
|
| 5523 | + | symbolId: sym.id, |
|
| 5524 | + | fullFnType: fullFnInfo, |
|
| 5521 | 5525 | }; |
|
| 5522 | 5526 | set self.methodsLen += 1; |
|
| 5523 | 5527 | } |
|
| 5524 | 5528 | ||
| 5525 | 5529 | /// Look up an instance entry by trait and concrete type. |
| 5542 | 5546 | } |
|
| 5543 | 5547 | } |
|
| 5544 | 5548 | return nil; |
|
| 5545 | 5549 | } |
|
| 5546 | 5550 | ||
| 5547 | - | /// Look up a standalone method entry by its symbol. |
|
| 5548 | - | export unsafe fn findMethodBySymbol 'arena (self: &Resolver 'arena, sym: *unsafe mut Symbol) -> ?*unsafe MethodEntry { |
|
| 5551 | + | /// Look up standalone method metadata by its resolver-local symbol identity. |
|
| 5552 | + | export fn findMethodBySymbol 'arena (self: &Resolver 'arena, symbolId: u32) -> ?MethodEntry { |
|
| 5549 | 5553 | for i in 0..self.methodsLen { |
|
| 5550 | - | let entry: *unsafe MethodEntry = &self.methods[i]; |
|
| 5551 | - | if entry.symbol == sym { |
|
| 5554 | + | let entry = self.methods[i]; |
|
| 5555 | + | if entry.symbolId == symbolId { |
|
| 5552 | 5556 | return entry; |
|
| 5553 | 5557 | } |
|
| 5554 | 5558 | } |
|
| 5555 | 5559 | return nil; |
|
| 5556 | 5560 | } |
lib/std/lang/resolver/tests/regions.rad
+24 -0
| 49 | 49 | assert last.mutable; |
|
| 50 | 50 | assert resolver::findTraitMethod(&info.methods[..], "missing") == nil; |
|
| 51 | 51 | } |
|
| 52 | 52 | } |
|
| 53 | 53 | ||
| 54 | + | /// Standalone method identities select independent registry entries. |
|
| 55 | + | @test unsafe fn testStandaloneMethodIdentityLookup() throws (testing::TestError) { |
|
| 56 | + | let mut arena = super::testArena(); |
|
| 57 | + | let storage: 'test = &mut arena in { |
|
| 58 | + | let mut res = super::testResolver(storage); |
|
| 59 | + | let result = try super::resolveProgramStr(&mut res, "record R {} fn (r: &R) first() {} fn (r: &mut R) second() {}"); |
|
| 60 | + | try super::expectNoErrors(&result); |
|
| 61 | + | let case ast::NodeValue::Block(block) = result.root.value else throw testing::TestError::Failed; |
|
| 62 | + | let firstSymbol = resolver::symbolFor(&res, block.statements[1]) else throw testing::TestError::Failed; |
|
| 63 | + | let lastSymbol = resolver::symbolFor(&res, block.statements[2]) else throw testing::TestError::Failed; |
|
| 64 | + | let first = resolver::findMethodBySymbol(&res, firstSymbol.id) else throw testing::TestError::Failed; |
|
| 65 | + | let last = resolver::findMethodBySymbol(&res, lastSymbol.id) else throw testing::TestError::Failed; |
|
| 66 | + | assert mem::eq(first.name, "first"); |
|
| 67 | + | assert not first.mutable; |
|
| 68 | + | assert mem::eq(last.name, "second"); |
|
| 69 | + | assert last.mutable; |
|
| 70 | + | assert first.fullFnType.paramTypes.len == 1; |
|
| 71 | + | assert first.fnType.paramTypes.len == 0; |
|
| 72 | + | assert last.fullFnType.paramTypes.len == 1; |
|
| 73 | + | assert last.fnType.paramTypes.len == 0; |
|
| 74 | + | assert resolver::findMethodBySymbol(&res, res.symbolCount) == nil; |
|
| 75 | + | } |
|
| 76 | + | } |
|
| 77 | + | ||
| 54 | 78 | /// Iteration over raw slices requires permission to read their storage. |
|
| 55 | 79 | @test unsafe fn testRawSliceIterationRequiresUnsafe() throws (testing::TestError) { |
|
| 56 | 80 | for program in [ |
|
| 57 | 81 | "fn f(p: *unsafe [u32]) { for item in p { assert item == 0; } }", |
|
| 58 | 82 | "fn f(p: *unsafe mut [u32]) { for item, index in p { assert item == index; } }", |