compiler: Resolve region indexes from checked declarations
287a66c83a052d4732fede6877de2f307bf1c91331806259bff4f52078bf7bcd
1 parent
deaafa1d
lib/std/lang/resolver.rad
+23 -22
| 6827 | 6827 | set arguments[i] = nil; |
|
| 6828 | 6828 | } |
|
| 6829 | 6829 | return RegionSubstitution { parameters, arguments }; |
|
| 6830 | 6830 | } |
|
| 6831 | 6831 | ||
| 6832 | - | /// Find the position of a region in a substitution's declared parameter list. |
|
| 6833 | - | unsafe fn regionParameter(map: &RegionSubstitution, region: *unsafe types::Region) -> ?u32 { |
|
| 6834 | - | for parameter, i in map.parameters.entries { |
|
| 6835 | - | if parameter.id == region.id { |
|
| 6836 | - | return i; |
|
| 6832 | + | /// Find a region's position among the region declarations in one scope. |
|
| 6833 | + | fn regionIndex(scope: &RegionScope, regionId: u32) -> ?u32 { |
|
| 6834 | + | match scope.declarations { |
|
| 6835 | + | case RegionDeclarations::Parameters(nodes) => { |
|
| 6836 | + | let mut index: u32 = 0; |
|
| 6837 | + | for node in nodes { |
|
| 6838 | + | let case ast::NodeValue::Region { .. } = node.value else continue; |
|
| 6839 | + | if node.id == regionId { |
|
| 6840 | + | return index; |
|
| 6841 | + | } |
|
| 6842 | + | set index += 1; |
|
| 6843 | + | } |
|
| 6844 | + | } |
|
| 6845 | + | case RegionDeclarations::Block(node) => { |
|
| 6846 | + | if node.id == regionId { |
|
| 6847 | + | return 0; |
|
| 6848 | + | } |
|
| 6837 | 6849 | } |
|
| 6838 | 6850 | } |
|
| 6839 | 6851 | return nil; |
|
| 6840 | 6852 | } |
|
| 6841 | 6853 |
| 6843 | 6855 | unsafe fn inferRegionClass 'arena ( |
|
| 6844 | 6856 | self: &mut Resolver 'arena, map: &RegionSubstitution, |
|
| 6845 | 6857 | expected: types::PointerClass, actual: types::PointerClass, site: *ast::Node |
|
| 6846 | 6858 | ) throws (ResolveError) { |
|
| 6847 | 6859 | let case types::PointerClass::Region(parameter) = expected else return; |
|
| 6848 | - | let index = regionParameter(map, parameter) else return; |
|
| 6860 | + | let index = regionIndex(map.parameters, parameter.id) else return; |
|
| 6849 | 6861 | let case types::PointerClass::Region(argument) = actual |
|
| 6850 | 6862 | else throw emitError(self, site, ErrorKind::RegionInference(parameter.name)); |
|
| 6851 | 6863 | if let previous = map.arguments[index]; previous.id <> argument.id { |
|
| 6852 | 6864 | throw emitError(self, site, ErrorKind::RegionInference(parameter.name)); |
|
| 6853 | 6865 | } |
| 6935 | 6947 | throw emitError(self, site, ErrorKind::RegionInference(parameter.name)); |
|
| 6936 | 6948 | } |
|
| 6937 | 6949 | } |
|
| 6938 | 6950 | for parameter, i in map.parameters.entries { |
|
| 6939 | 6951 | let parent = parameter.parent else continue; |
|
| 6940 | - | let index = regionParameter(map, parent) else panic "validateRegionArguments: unknown parent"; |
|
| 6952 | + | let index = regionIndex(map.parameters, parent.id) else panic "validateRegionArguments: unknown parent"; |
|
| 6941 | 6953 | let parentArgument = map.arguments[index] else panic "validateRegionArguments: missing parent argument"; |
|
| 6942 | 6954 | let argument = map.arguments[i] else panic "validateRegionArguments: missing argument"; |
|
| 6943 | 6955 | if not types::regionContains(parentArgument, argument) { |
|
| 6944 | 6956 | throw emitError(self, site, ErrorKind::RegionParent(parameter.name)); |
|
| 6945 | 6957 | } |
| 6947 | 6959 | } |
|
| 6948 | 6960 | ||
| 6949 | 6961 | /// Substitute a reference's region while preserving its ownership class. |
|
| 6950 | 6962 | unsafe fn substituteRegionClass(map: &RegionSubstitution, class: types::PointerClass) -> types::PointerClass { |
|
| 6951 | 6963 | let case types::PointerClass::Region(region) = class else return class; |
|
| 6952 | - | let index = regionParameter(map, region) else return class; |
|
| 6964 | + | let index = regionIndex(map.parameters, region.id) else return class; |
|
| 6953 | 6965 | let argument = map.arguments[index] else panic "substituteRegionClass: missing argument"; |
|
| 6954 | 6966 | return types::PointerClass::Region(argument); |
|
| 6955 | 6967 | } |
|
| 6956 | 6968 | ||
| 6957 | 6969 | /// Substitute free region arguments in a type without changing its runtime layout. |
|
| 6958 | 6970 | unsafe fn substituteRegions 'arena (self: &mut Resolver 'arena, map: &RegionSubstitution, ty: Type) -> Type { |
|
| 6959 | 6971 | match ty { |
|
| 6960 | 6972 | case Type::Cell { class, payload } => |
|
| 6961 | 6973 | return Type::Cell { class: substituteRegionClass(map, class), payload: allocType(self, substituteRegions(self, map, *payload)) }, |
|
| 6962 | 6974 | case Type::Session(region) => { |
|
| 6963 | - | let index = regionParameter(map, region) else return ty; |
|
| 6975 | + | let index = regionIndex(map.parameters, region.id) else return ty; |
|
| 6964 | 6976 | let argument = map.arguments[index] else panic "substituteRegions: missing session region"; |
|
| 6965 | 6977 | return Type::Session(argument); |
|
| 6966 | 6978 | } |
|
| 6967 | 6979 | case Type::Pointer { class, target, mutable } => { |
|
| 6968 | 6980 | let targetType = substituteRegions(self, map, *target); |
| 10106 | 10118 | ||
| 10107 | 10119 | /// Return whether a region identity is visible in a lexical environment. |
|
| 10108 | 10120 | fn regionInScope(scope: ?*RegionScope, regionId: u32) -> bool { |
|
| 10109 | 10121 | let mut cursor = scope; |
|
| 10110 | 10122 | while let current = cursor { |
|
| 10111 | - | match current.declarations { |
|
| 10112 | - | case RegionDeclarations::Parameters(nodes) => { |
|
| 10113 | - | for node in nodes { |
|
| 10114 | - | if let case ast::NodeValue::Region { .. } = node.value; node.id == regionId { |
|
| 10115 | - | return true; |
|
| 10116 | - | } |
|
| 10117 | - | } |
|
| 10118 | - | } |
|
| 10119 | - | case RegionDeclarations::Block(node) => { |
|
| 10120 | - | if node.id == regionId { |
|
| 10121 | - | return true; |
|
| 10122 | - | } |
|
| 10123 | - | } |
|
| 10123 | + | if regionIndex(current, regionId) <> nil { |
|
| 10124 | + | return true; |
|
| 10124 | 10125 | } |
|
| 10125 | 10126 | set cursor = current.parent; |
|
| 10126 | 10127 | } |
|
| 10127 | 10128 | return false; |
|
| 10128 | 10129 | } |
lib/std/lang/resolver/tests/regions.rad
+16 -0
| 585 | 585 | let err = try super::expectError(&result); |
|
| 586 | 586 | let case resolver::ErrorKind::BorrowConflict(_) = err.kind else throw testing::TestError::Failed; |
|
| 587 | 587 | } |
|
| 588 | 588 | } |
|
| 589 | 589 | ||
| 590 | + | /// Ownership markers do not change the positions of nominal region arguments. |
|
| 591 | + | @test unsafe fn testNominalRegionParameterOrder() throws (testing::TestError) { |
|
| 592 | + | for program in [ |
|
| 593 | + | "record Pair: Copy + 'a + 'b { left: &'a u32, right: &'b u32 } fn f 'x 'y (left: &'x u32, right: &'y u32) -> Pair 'x 'y { return Pair 'x 'y { left, right }; }", |
|
| 594 | + | "record Pair: 'a + Copy + 'b { left: &'a u32, right: &'b u32 } fn f 'x 'y (left: &'x u32, right: &'y u32) -> Pair 'x 'y { return Pair 'x 'y { left, right }; }", |
|
| 595 | + | "record Pair: 'a + 'b + Copy { left: &'a u32, right: &'b u32 } fn f 'x 'y (left: &'x u32, right: &'y u32) -> Pair 'x 'y { return Pair 'x 'y { left, right }; }", |
|
| 596 | + | ] { |
|
| 597 | + | let mut arena = super::testArena(); |
|
| 598 | + | let storage: 'test = &mut arena in { |
|
| 599 | + | let mut res = super::testResolver(storage); |
|
| 600 | + | let result = try super::resolveProgramStr(&mut res, program); |
|
| 601 | + | try super::expectNoErrors(&result); |
|
| 602 | + | } |
|
| 603 | + | } |
|
| 604 | + | } |
|
| 605 | + | ||
| 590 | 606 | /// Exact arguments share one descriptor and all applications share the source layout. |
|
| 591 | 607 | @test unsafe fn testNominalRegionApplications() throws (testing::TestError) { |
|
| 592 | 608 | let mut testArena19 = super::testArena(); |
|
| 593 | 609 | let testStorage19: 'test19 = &mut testArena19 in { |
|
| 594 | 610 | let mut res = super::testResolver(testStorage19); |